/* * romapi.h -- the VT1200 firmware entry points a C payload may call. * * Every address here is a TMS34010 BIT address (= Ghidra byte address x 8). * The evidence for each is dwt/notes/TCPIP.md (sockets) and dwt/notes/HEAP.md * (allocator); the ones marked "verified live" have been called from a payload * on real hardware, not just read out of the ROM. * * K&R C only. This compiler rejects ANSI prototypes (`int f(int a)` is a * syntax error), so the declarations below are old-style: the parameter lists * live in the comments, and the compiler checks nothing but the name. That is * the price of using the 1987 toolchain; keep the comments honest. * * Calling convention: the C compiler and the firmware agree -- arguments are * widened to 32 bits and pushed upward on the program stack (A14), first * argument last, and the result comes back in A8. The thunks in entry.asm * forward with `calla`, so the caller's already-pushed arguments pass through * untouched and only A8 has to survive. */ #ifndef ROMAPI_H #define ROMAPI_H /* ---- ROM entry points -------------------------------------------------- */ #define ROM_SOCKET 0x3F5C9A00 /* Ghidra 07EB9340 verified live */ #define ROM_BIND 0x3F5CAA80 /* Ghidra 07EB9550 BOOTP caller */ #define ROM_LISTEN 0x3F5CBCD0 /* Ghidra 07EB979A inetd caller */ #define ROM_ACCEPT 0x3F5CCB40 /* Ghidra 07EB9968 inetd caller */ #define ROM_SENDTO 0x3F5D3D70 /* Ghidra 07EBA7AE verified live */ #define ROM_RECVFROM 0x3F5D7D50 /* Ghidra 07EBAFAA verified live */ #define ROM_READ 0x3F5D8E70 /* Ghidra 07EBB1CE rdebug / Xlib */ #define ROM_CLOSE 0x3F5E8930 /* Ghidra 07EBD126 verified live */ #define ROM_SETSOCKOPT 0x3F5DD260 /* Ghidra 07EBBA4C BOOTP / Xlib */ #define ROM_DELAY 0x3F833A20 /* Ghidra 07F66744 sleep(ms), telnet caller */ #define ROM_SELECT 0x3F871CE0 /* Ghidra 07F0E39C Xlib caller, candidate */ #define ROM_MALLOC 0x3F701230 /* Ghidra 07EE0246 verified live */ #define ROM_FREE 0x3F702440 /* Ghidra 07EE0488 allocator */ #define ROM_CREATE_PROC 0x3F706A40 /* Ghidra 07EE0D48 GUI work */ /* ---- thunks implemented in entry.asm ----------------------------------- */ /* * int socket_(domain, type, protocol) -> fd, or -1 * int bind_(fd, sockaddr *, len) -> 0, or -1 * int recvfrom_(fd, buf, len, flags, from *, fromlen *) * -> bytes, or -1 * int close_(fd) -> 0, or -1 * unsigned int malloc_(bytes) -> BIT pointer, or 0 * int free_(bit pointer) -> 0 * * `from` is a 16-byte sockaddr the stack fills in; `fromlen` points to an * int that must be 16 on entry (the call writes back the real length). */ int socket_(); int bind_(); int recvfrom_(); int close_(); int listen_(); int accept_(); int read_(); int select_(); int delay_(); unsigned int malloc_(); int free_(); /* ---- socket constants -------------------------------------------------- */ #define AF_INET 2 #define SOCK_DGRAM 2 #define SOCK_STREAM 1 #define IPPROTO_UDP 0 #define SOCKADDR_LEN 16 /* * struct sockaddr, 16 bytes, NETWORK byte order: * +0 u16 family (AF_INET = 2 -> bytes 00 02) * +2 u16 port (high byte first, e.g. 7000 = 0x1B58 -> 1B 58) * +4 u32 addr (0 = INADDR_ANY) * +8 u8 zero[8] */ /* Fill sa (an unsigned char[16]) with AF_INET, `port`, and INADDR_ANY. * `port` is in host order so callers can write 7000 rather than 0x1B58. */ static void sa_any(sa, port) unsigned char *sa; unsigned int port; { sa[0] = 0; sa[1] = AF_INET; sa[2] = (port >> 8) & 0xFF; sa[3] = port & 0xFF; sa[4] = 0; sa[5] = 0; sa[6] = 0; sa[7] = 0; sa[8] = 0; sa[9] = 0; sa[10] = 0; sa[11] = 0; sa[12] = 0; sa[13] = 0; sa[14] = 0; sa[15] = 0; } #endif /* ROMAPI_H */