joeylib2/tools/iigsStart/iigsStart.c

121 lines
4.4 KiB
C

// iigsStart -- a GS/OS boot launcher for the headless IIgs harnesses.
//
// Installed as /System/Start on a copy of the GS/OS system disk, this runs
// at boot INSTEAD of the Finder and hands off to one JoeyLib example. The
// point is that the Finder cannot be driven from a script: measured under
// gssquared, injected keystrokes reach the $C000 latch but never reach the
// Finder -- Open-Apple-A, Tab, arrows and bare letters all left the desktop
// untouched. (The one redraw seen after the first key of a run is the
// Finder's own settling: byte-identical for three different keys.) Reaching
// the desktop also costs ~61s of boot that a probe must sit through; this
// route has the example on screen in ~52s.
//
// Two GS/OS calls, in this order:
// SetPrefixGS -- point prefix 0 at the example's DIRECTORY. GS/OS does
// NOT do this for a QuitGS launch; prefix 0 was measured still pointing
// at the boot volume. That is not cosmetic: JoeyLib opens its NTP
// replayer as bare "ntpplayer", and when that read fails jlpAudioInit
// returns before ntpArm(), so the sound interrupt vector stays at its
// ROM default ($E1002C = 5C xxxx FF) and the example is SILENT. The
// Finder sets prefix 0 itself, which is why this only bites here.
// QuitGS with pCount = 2 and a pathname -- "quit, and launch this".
//
// Build: clang-build.sh -DJOEY_START_PATH='"/JOEYLIB/STAXI"' \
// -o START iigsStart.c iigsStartQuit.s
#include <stdint.h>
// The program to launch. Overridden per-disk from the build.
#ifndef JOEY_START_PATH
#define JOEY_START_PATH "/JOEYLIB/STAXI"
#endif
// Fixed scratch in bank $E1: the $E1:9DC8-$9DFD window that survives a
// present (SCB proper ends at $9DC7). The asm stubs hard-code the two
// parameter-block addresses, so these must agree with iigsStartQuit.s.
// 9DC8 mailbox 9DCC QuitGS parm (8)
// 9DD4 pathname string 9DE4 SetPrefix parm (8)
// 9DEC prefix string
#define QUIT_MAILBOX ((volatile uint8_t *)0xE19DC8L)
#define QUIT_PARM ((volatile uint8_t *)0xE19DCCL)
#define QUIT_PATH ((volatile uint8_t *)0xE19DD4L)
#define PREFIX_PARM ((volatile uint8_t *)0xE19DE4L)
#define PREFIX_PATH ((volatile uint8_t *)0xE19DECL)
#define QUIT_PATH_ADDR 0x00E19DD4UL
#define PREFIX_PATH_ADDR 0x00E19DECUL
// A GS/OS class-1 input string is a length WORD followed by the characters.
#define GSOS_STRING_HEADER 2u
// Markers for the harness.
#define QUIT_REACHED 0xAAu
#define QUIT_RETURNED 0xEEu
void iigsStartQuit(void);
void iigsStartSetPrefix(void);
// Write a GS/OS input string (length word + characters) and return its length.
static uint16_t gsosString(volatile uint8_t *dst, const char *src, uint16_t len) {
uint16_t i;
dst[0] = (uint8_t)(len & 0xFFu);
dst[1] = (uint8_t)((len >> 8) & 0xFFu);
for (i = 0; i < len; i++) {
dst[GSOS_STRING_HEADER + i] = (uint8_t)src[i];
}
return len;
}
static void putLong(volatile uint8_t *dst, uint32_t v) {
dst[0] = (uint8_t)(v & 0xFFu);
dst[1] = (uint8_t)((v >> 8) & 0xFFu);
dst[2] = (uint8_t)((v >> 16) & 0xFFu);
dst[3] = (uint8_t)((v >> 24) & 0xFFu);
}
int main(void) {
const char *path = JOEY_START_PATH;
uint16_t len = 0;
uint16_t dir = 0;
uint16_t i;
while (path[len] != '\0') {
len++;
}
// Directory part, including the trailing '/': everything up to the last
// separator. "/JOEYLIB/STAXI" -> "/JOEYLIB/".
for (i = 0; i < len; i++) {
if (path[i] == '/') {
dir = (uint16_t)(i + 1u);
}
}
gsosString(PREFIX_PATH, path, dir);
PREFIX_PARM[0] = 2u; // pCount
PREFIX_PARM[1] = 0u;
PREFIX_PARM[2] = 0u; // prefixNum 0 = current directory
PREFIX_PARM[3] = 0u;
putLong(PREFIX_PARM + 4, PREFIX_PATH_ADDR);
iigsStartSetPrefix();
gsosString(QUIT_PATH, path, len);
QUIT_PARM[0] = 2u; // pCount
QUIT_PARM[1] = 0u;
putLong(QUIT_PARM + 2, QUIT_PATH_ADDR); // pathname
QUIT_PARM[6] = 0u; // flags
QUIT_PARM[7] = 0u;
*QUIT_MAILBOX = QUIT_REACHED;
iigsStartQuit();
*QUIT_MAILBOX = QUIT_RETURNED;
// QuitGS only returns on failure. Nothing useful is left to do and the
// llvm-mos post-main exit path is broken on GS/OS, so spin rather than
// crash: the harness reads the mailbox to see what happened.
for (;;) {
}
}