Syscalls

From WikiPrizm
Jump to: navigation, search

If you are looking for the list of syscalls, see Category:Syscalls instead.

This page has not been completed. Parts may be missing or reorganized before completed. Information is provided as-is and may have errors.

The version of CASIOWIN on the Prizm supports system calls, like on previous models such as the fx-9860G and similar. On this Wiki, system calls are usually abbreviated as syscalls.

Most of the addresses on the table of system calls are entry-points to functions, but some of the addresses point to data like glyph tables.

A list of the known syscalls that correspond to functions is available here.

Much of the information on this page may be considered to be of optional reading to a beginner. In fact, understanding how syscalls work, their numbers, how parameters are passed, etc. is not critical to writing an application (add-in) for the Casio Prizm, as at the C-language level, they are like any other functions. However, having deeper knowledge of these subjects may be of benefit to people planning to program in assembly, do manual code optimization, reverse engineering or lower-level stuff in general.

Calling convention

To access a system call, code should jump to 0x80020070 with the syscall number in register R0. After the syscall is executed, it will jump back to the calling code.

MOV.L   syscall_number, R0
MOV.L   #H'80020070, R2
JMP     @R2
NOP
NOP     ; execution will resume here

The NOP after the JMP is necessary because in the SH-4 instruction set, JMP is a delayed branch instruction (the instruction after the JMP will execute before the jump occurs). The second NOP could really be anything (your code).

Syscall numbers

The numbers for the syscalls are documented on the Wiki page for each one. Note that the syscalls documented, and their numbers, refer to the Prizm models (fx-CG10 and fx-CG20), not the fx-9860G and alikes! Some syscalls have corresponding versions in the CASIOWIN that runs on these previous models, but others are new and others have changed behavior despite sharing the same signature.

What is available as syscalls

Most OS functions, even insignificant ones, appear to be exposed as syscalls. Most likely, in the build process of the OS, a syscall table is exported, based on all the functions (and possibly other symbols) found in the code, and put at a specific place in the resulting OS binary. Of course, in order to guarantee that add-ins stay compatible across OS versions, the system used to build this table must keep numbers for existing syscalls the same across builds.

The support for syscalls is essential for add-ins to work. Official add-ins are most likely linked against the syscall table as generated during the OS build process. This would allow for coding add-ins using the same function names as used the core OS code.

Apparently certain libraries, such as zlib (included for decoding and encoding of g3p pictures), are not exposed directly through syscalls. This can be due to the fact that the OS code is linked against a cross-compiled zlib, but zlib source files are not present in the OS code tree, so its functions escape being included in the syscall table during the build process.

What uses syscalls

Apart from add-ins, it is not clear whether internal apps also use the syscall calling convention (i.e., jump to 0x80020070) to call core OS functions.

How they work

Syscalls are based upon a table whose entries are mostly function pointers - as explained above, not every entry in the syscall table corresponds to a pointer to a function. There is no form of validation on the syscall number being called, to see if it corresponds to a table entry for a function (i.e., no bounds checking nor type checking) so make sure you are calling a valid syscall. In the Calling convention section you may have noticed that each syscall has an unique number. This does not necessarily mean that all different values correspond to a different function. You may also have noticed that we are using the jmp instruction to go to address 0x80020070. This is a physical address on the flash memory and the code starting at that address is:

! ---------------------------------------------------------------------------
                mov.l   #SyscallJumpTable, r2
                shll2   r0
                mov.l   @(r0,r2), r0
                jmp     @r0
                nop

This code takes the syscall number, multiplies it by four (pointers are four bytes, as the Prizm CPU is a 32-bit SH-4), then gets the pointer to the function at that offset, and jumps to the address that was just retrieved. Program execution resumes where it left off, because the functions available as syscalls end with the instruction rts (return from subroutine) - since the syscall was called as a routine (i.e. with jsr, not present in the shown code), the value in the PR (procedure register) is the one which the PC (program counter) will be changed to, obviously resuming the execution on your code after the call to the syscall.