nocash wrote:
Operating system
I know that there are SVC (aka SWI) functions, but they seem to cover only stuff like thread creation. I assume that there are also OS functions for file IO and perhaps even GUI functions? I have spotted docs with command numbers or function numbers for OS functions... but how would one invoke such a function number?
A short description for getting started on using OS functions would be nice! Or some small binary and/or sample source code for something like file io.
Disclaimer: I have never worked with the 3DS, but I do know how it works on the Switch, and the Switch kernel was based on the 3DS one, so they are pretty similar.
They are invoked by using the SendSyncRequest SVC (this is SVC number number 0x32 according to 3dbrew). First, you need to get the session handle for the service you want to communicate with. You can do that by calling the GetServiceHandle function on the Srv (Service Manager) service. This handle can be then used to send messages to the service by using SendSyncRequest. As the name implies, this is a synchronous request, so the calling thread will be put into wait state, and execution is resumed on that thread only when the response to your request is sent back.
Inter-process Communication (IPC) messages:
Communication with services is done with the use of messages. They store things like the command number of the function you want to call, the parameters passed to that function, and also other related information (such as possible buffers also passed to the function, handles etc). Similary, response messages are written at the same place (they overwrite the request message) and use a similar structure. This mechanism allows processes to communicate with each other on the 3DS OS.
The message that is sent to the service should be stored on the Thread Local Storage (TLS), a per-thread 0x200 bytes memory region reserved by the kernel on thread creation. The IPC message is always written at offset 0x80 within the TLS. At the server side, messages can be received by using the ReplyAndReceive SVC (this one is not normally accessible for applications, only the services should use it to reply IPC messages). ReplyAndReceive, as the name implies, is responsible for doing 2 things. First, it replies a request that was previously processed, and then it picks one incoming message on the queue for processing. If the queue is empty, then it simply waits for a message to arrive, during that time the thread will be in wait state.
The kernel is responsible for copying the request messages from the client to the server, and copying reply messages from the server to the client. They are both written at the same address (TLS + 0x80), and the reply message will simply overwrite the request message.
When SendSyncRequest returns, you're supposed to read the reply from the TLS. Normally, it will contain a result code, and depending on what you called, it may also contain more data after that. For some functions, you're also supposed to pass buffers (basically, just a address and size) on the request, where you pass large data to the function, or it can also be used by the service function to write large data that will be returned to you.
Simplified process:
To sum it up, the process is basically like this for invoking a service function:
- Call the ConnectToPort SVC, and pass on name "srv:" to get a handle for the SRV service. (You only need to do that once, you can then store the handle somewhere for later use).
- Call Srv GetServiceHandle function, using the above handle and SendSyncRequest, to get a session handle for the service you want to communicate with, writing the service name on the IPC message (that is the function parameter). The service names usually contains a `:` followed by a character that indicates privilege level. For example, `:u` stands for "user privilege". (You only need to do that once
per-service).
- Call SendSyncRequest using the session handle returned from GetServiceHandle to call the desired function. The command number and parameters passed to the function should be written to the IPC message.
- After the above call returns, read the IPC message to get the response, including the result code and possibly other data depending on the function.
References:
The structure of the IPC messages is documented at:
https://www.3dbrew.org/wiki/IPC#Message_Structure
On that page, you can also find a brief explanation of sessions and ports (they are confusing, at least to me).
Documentation of the SVCs can be found at:
https://www.3dbrew.org/wiki/SVC#System_calls
The documentation is not complete however. And in a lot of cases, they are not clear about what the SVCs actually do.
Edit:
For file I/O, I believe you're looking for this service:
https://www.3dbrew.org/wiki/Filesystem_services