PalmOS on x86: API porting

Implementing PalmOS on x86 is exactly what it sounds: picking each function described in the official API and providing an implementation. It may look a little intimidating at first, but this is one of those things that follow the 80/20 rule: 80% of the applications out there use only 20% of the API.  Take for example this excerpt from Core/System/StringMgr.h header file:

Char *StrCopy(Char *dst, const Char *src) SYS_TRAP(sysTrapStrCopy);
Char *StrNCopy(Char *dst, const Char *src, Int16 n) SYS_TRAP(sysTrapStrNCopy);
UInt16 StrLen(const Char *src) SYS_TRAP(sysTrapStrLen);

On actual PalmOS, these function are implemented using system traps, like any other function in the API. I started by creating a script that automatically converts each header file in the PalmOS SDK to a stub C implementation. The functions do nothing but output a warning message on stderr and return a dummy value so that the compiler is happy:

Char *StrCopy(Char *dst, const Char *src) {
debug("%s not implemented", __FUNCTION__);
return NULL;
}

Char *StrNCopy(Char *dst, const Char *src, Int16 n) {
debug("%s not implemented", __FUNCTION__);
return NULL;
}

UInt16 StrLen(const Char *src) {
debug("%s not implemented", __FUNCTION__);
return 0;
}

Here __FUNCTION__ is a handy constant handled by GCC that contains a string representation of the function name being compiled. When I compile a PalmOS application and link it to my stub library, there should be no undefined symbol messages.

After that, it was a matter of selecting the “most important” functions (remember the 80/20 rule) and providing an concrete implementation. In my port, the functions shown above are implemented using similar functions from the POSIX API on the host system (Linux). Here is the equivalent port on StringMgr.c:

Char *StrCopy(Char *dst, const Char *src) {
if (dst && src) {
strcpy(dst, src);
}
return dst;
}

Char *StrNCopy(Char *dst, const Char *src, Int16 n) {
if (dst && src) {
strncpy(dst, src, n);
}
return dst;
}

UInt16 StrLen(const Char *src) {
return src ? strlen(src) : 0;
}

PalmOS API functions can be placed in three categories:

  • Functions that have a direct equivalent on the host system (like the ones above);
  • Functions that have no equivalent, but are simple enough so I can deduce the behavior;
  • Complex functions that have no equivalent.

An example of the second category is:

void RctOffsetRectangle(RectangleType *rP, Coord deltaX, Coord deltaY) {
if (rP) {
rP->topLeft.x += deltaX;
rP->topLeft.y += deltaY;
}
}

Usually the description found on the PalmOS Programmer’s API Reference documentation is enough for a general understanding of the expected behavior. The real problem is the third category. What exactly FrmInitForm() does to the structure of a FormType ? How does FldSetText() manage the memory handle passed in ? This is where I spent half of the time with this project. Trying to figure out what the heck is going on under the hood.

Another hard problem is mapping concepts unique to PalmOS to the host system. On Linux memory can be seen as a very big byte array. Call malloc() to get a portion of this array, the call free() when you do not need it anymore. Use I/O file functions to write those arrays to disk, if needed. On classic PalmOS there is no filesystem: dynamic memory and databases are mapped to memory “chunks”. Chunks belong to memory heaps, and can be either fixed or movable. Record editing is usually done “in place”. Most of these concepts are completely alien to modern desktop systems. This is where I spent the other half of the time.

The current status of the code is pre-alpha. Like I said before, there are still some functions that were not implemented. Some functions work in some cases, but not in others, because of my limited knowledge about the actual behavior.

I took my applications written for PalmOS a long time ago and tried to make them run on this port. I was glad to see that ptelnet is completely usable. As a benchmark, I also took the MemoPad source code from the samples folder on PalmOS Development Suite (PODS). It mostly works now, but there are  a few corner cases that need refinement.

5 thoughts on “PalmOS on x86: API porting

  1. I am not familiar with tiled wm, but in theory this port could run on any Linux device. Micro controllers like Arduino are not capable of running it.

    Like

  2. is possible using tiled wm like w3m or regolith linux?
    palm created for one program on desktop in this same time, very similar to tiled wm.

    is possible run this on microcontroler like arduino, rpi2040, pic M0 ARM, qomu fpga?

    Like

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Google photo

You are commenting using your Google account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s