if you start programming in kernel mode, sooner or later your program will crash when accessing a kernel function... well, there is a quick solution to this in the latest pspsdk: pspKernelSetKernelPC()
looks like someone else met the problem;)
i consider that ppl should know why this is happening so i'll try to explain in detail the problem:
1. PSP memory map is like this
virtual memory
from 00000000 1G user seg cached
from 40000000 1G user seg uncached
from 80000000 0.5 G kern seg cached
from a0000000 0.5 G kern seg uncached
how the mem mapping to physical is done is not important for now
2. executables that are built with psp-toolchain have a starting address of 08900000 (user seg cached), even for kernel mode elfs!!!
this is built in for now in the linker. well, you can have the linker use another link script or relocate your elf, but that will not help you. psp will not like it (800200D9-memblock alloc failed)
3. so here's the first catch
the pspsdk startup code (in crt0.c) is fixing the address of the main thread for kernel modules; it ORs a 80000000 to main function pointer. then it creates a thread for it - that means that we will have the PC running in upper half of address space. that is very important because regular call instructions (j and jal) use the upper bits of PC to make the new program counter - ie. they keep the segment.
4. all is fine with the code above unless you create a new (kernel mode) thread that calls kernel(-only) functions or you use a switch statement (that have lots of cases). why?
a. for a thread, in most cases u use the entry point address that is provided by compiler like this
-----8<------
thp.entry = SomeThread;
CreateThread(&thp);
----->8------
the solution is to remember that when you have to create a kernel mode thread you have to OR the entry point address with 80000000 like in crt0.c code ;)
b. switch statements that have few cases are coded by compiler as a chain of if-else; so it is fine. if you have more cases you'll get a jump table; you don't want that if you're in kernel mode! because all the jump addresses have user space prefix (0890xxxx and shit); remember that your executable was linked as user mode - see paragraph (2.) above
you have 2 solutions: you code yourself the switch as if-else chain or use pspKernelSetKernelPC() function on each case branch that calls kernel functions. at the end of the function you'll be fine because the PC is restored from RA (which was saved).
c. i haven't met (yet) another case when the PC goes user mode. i dislike to use the pspKernelSetKernelPC() function before every call to kernel functions. so i guess if you take care of the 2 cases above you'll be ok.
I am sorry for too many details:P and I'll use this opportunity to say that i appreciate very much the work put in pspsdk. its devs know very well how the things work ;) great stuff
5. final comment on virtual to physical mapping
it appears that the physical 00000000-00800000 (first 8M) are mapped to virtual 88000000-88800000 (Cached) and a8000000-a8800000 (Uncached) and 00800000-02000000 (next 24M) are mapped to virtual 08800000-0a000000 (Cached) and 48800000-4a000000 (Uncached)
the upper 24M are also mapped to 88800000-8a000000, but when you try access the lower 8M at 08000000-08800000 you get an exception (bus error), hm... not quite symetrical
trick about kernel mode
It's also worth mentioning that several pspsdk samples demonstrate a clean way to use pspKernelSetKernelPC. They execute kernel functions in the constructor method, then execute the main thread in the mode specified by PSP_MAIN_THREAD_ATTR. Here's a snippet from usb/storage/main.c:
Code: Select all
/**
* Function that is called from _init in kernelmode before the
* main thread is started in usermode.
*/
__attribute__ ((constructor))
void loaderInit()
{
pspKernelSetKernelPC();
pspSdkInstallNoDeviceCheckPatch();
pspDebugInstallKprintfHandler(NULL);
}
-
- Posts: 47
- Joined: Wed Dec 15, 2004 4:23 am
that will not save you from troubles when running in kernel mode. every time you create a new kernel thread you have to OR the entry with 0x80000000. and every time you are have a big switch statement (ie. a jump table) you'll be again in user address space after each case label till the end of the function - so you'll need to call pspKernelSetKernelPC() again!!rinco wrote:It's also worth mentioning that several pspsdk samples demonstrate a clean way to use pspKernelSetKernelPC.
notice also that the $gp reg is having a user address space value.
----------------
not realy related to the subject here are some flags for thread creation
PSP_THREAD_ATTR_SCRATCH_SRAM = 0x00008000,
PSP_THREAD_ATTR_NO_FILLSTACK = 0x00100000,
PSP_THREAD_ATTR_CLEAR_STACK = 0x00200000,
if someone will care to add them to the lib...
With the exception of *_CLEAR_STACK, what do they do?florinsasu wrote:not realy related to the subject here are some flags for thread creation
PSP_THREAD_ATTR_SCRATCH_SRAM = 0x00008000,
PSP_THREAD_ATTR_NO_FILLSTACK = 0x00100000,
PSP_THREAD_ATTR_CLEAR_STACK = 0x00200000,
if someone will care to add them to the lib...
-
- Posts: 47
- Joined: Wed Dec 15, 2004 4:23 am
PSP_THREAD_ATTR_SCRATCH_SRAM is not used in firmware 1.0, if you put it in you will get an illegal attr error; basicaly it should allow using of scratchpad memory for a thread;mrbrown wrote:With the exception of *_CLEAR_STACK, what do they do?florinsasu wrote:not realy related to the subject here are some flags for thread creation
PSP_THREAD_ATTR_SCRATCH_SRAM = 0x00008000,
PSP_THREAD_ATTR_NO_FILLSTACK = 0x00100000,
PSP_THREAD_ATTR_CLEAR_STACK = 0x00200000,
if someone will care to add them to the lib...
PSP_THREAD_ATTR_NO_FILLSTACK disables the fill with 0xFF of the stack on creation
PSP_THREAD_ATTR_CLEAR_STACK will clear the stack when the thread is deleted
Edit: PSP_THREAD_ATTR_SCRATCH_SRAM is not used either in 1.5x
so i think it should be commented out for the moment;
the masks of allowed attribute flags are:
1.0X - 0xF03040FF
1.5X - 0xF83040FF
2.00 - ?
the lower byte seems to be reserved for internal use
Last edited by florinsasu on Wed Sep 28, 2005 12:18 am, edited 2 times in total.