Skip to content

Introducing Venix binary compatibility on TLVC#248

Open
Mellvik wants to merge 3 commits into
masterfrom
v7compat
Open

Introducing Venix binary compatibility on TLVC#248
Mellvik wants to merge 3 commits into
masterfrom
v7compat

Conversation

@Mellvik

@Mellvik Mellvik commented Jul 13, 2026

Copy link
Copy Markdown
Owner

This PR is the first in a series that will add software development capability to TLVC: A Complete set of Unix V7 software development tools - plus a number of other tools that some of us have been missing on ELKS and TLVC since forever.

The enabler - and starting point - is Venix/86: A complete and almost pure commercial Unix V7 system from 1983/84, first available on small PDP/11 systems, then ported to the x86 PC platform. More about Venix in the upcoming background Wiki document.

'Allmost pure' in this context means 'somewhat enhanced': Venix includes some BSD originated enhancements like vi, more, csh. Again, more details about all this in an upcoming Wiki document (probably several).

This PR which covers the kernel changes which make TLVC Venix/86 compatible. The result of a several months long experiment which started with a completely different goal: To understand Venix binaries enough to evaluate the feasability of getting some of them to run on TLVC via disassembly/reassembly. Another long story with lots of interesting experiences that needs its own Wiki.

The kernel changes (or enhancements if you like) fall into two distinctive groups: Syscalls and exec. A complete 'shim' syscall layer was created to emulate Venix kernel syscalls using TLVC's own syscalls - an obvious requirement for true binary compatibility. After first building tools to disassemble and more or less automatically rewrite Venix apps with a syscall 'adaption layer', which turned out to be too complicated, binary compatibility became the obvious solution. At that point, the knowledge gathered about how Venix apps and the Venix syscall layer worked, binary seemed within reach.

Venix syscalls are made through INT 0xf1 (TLVC native syscalls use INT 0x80). Parameter passing in registers in and out is well documented in the available documentation. The implementation traps syscalls right next to the native ones in irqtab.S, arguments adapted to TLVC syscalls if necessary - inside the syscall code. On exit a similar process puts registers and error returns where Venix expects them. Not trivial, but not all that complicated either.

The changes required in the syscalls themselves were untrivial in some cases: Some were missing, some had different parameter passing regimes - in particular longs. And some, sys_exec in particular, needed major rework. First in order to convert the parameters from Venix to TLVC, then to understand, load and execute Venix binaries as is.

Part of the challenge was the obvious need for the modified syscalls to know the origin of the call - V7 or native - in order to do the right thing. A challenge that initially seems rather simple, but soon enough got complicated by the fact that some syscalls call other syscalls which then are native rather than Venix-originated. Details about the trickery needed to resolve this in the technical Wiki - and in comments in the code - exec.c and ìrqtab.S`in particular. About 20 syscalls needed rework, the rest are either OK as is or not used/didn't exist when V7 was around.

As already mentioned, sys_exec first got a significant addition to massage the arguments into the format required by TLVC. Incidentally almost exactly the same process that the TLVC library layer does before passing the call on to the kernel. Non-trivial in size but unavoidable. Then, when the decision had been made to go for binary compatibility, code to handle two new binary formats was needed. Not all that complicated but time consuming: There are many moving parts in this machine, and TLVC has not been exposed to tiny model binaries before. Also, stack and heap handling is different in Venix (discussed separately).

Finally, while not using the medium memory model, Venix still has the capability of running binaries with text > 64k. The magic is 'code mapping', inherited from the PDP/11 and implemented via software interrupt 0xf5. There are only a few applications in Venix/86 that actually use this mechanism, vi and basic being two of them. And since we have perfectly viable versions of both already, code mapping has not (yet) been implemented. By the way, we do have the sources to the vi in question, from BSD 2.9, and can port it (instead of using the binary) if we like.

While on the issue of software interrupts, Venix/86 uses 5 of them: 0xf1 = syscalls, 0xf2 = stack trap, 0xf3 = abort process, 0xf4 = floating point selector (FPU or code), 0xf5 = code mapping). Details in Wiki.

V7 compatibility in TLVC is entirely optional. CONFIG_COMPAT_V7, available from menuconfig, includes or excludes the enhancements completely, kernel and applications.

Apropos applications: Some obviously need changes to recognize and handle the 'new world': ps, meminfo, chmem in particular. The latter is already operational, all are coming in a later PR.

A word about motivation: Is an ancient collection of software development tools that valuable? I think so. While making TLVC selfcompiling is a no-go because the current, gcc-based toolkit for building the system is so much better than the old one, the 'Unix software tools' makes the system more complete and more interesting to work with. By the way, while some of the tools require binary compatibility because source code is not available, other V7 tools are easily ported. Along the way, some have indeed been ported to TLVC, directly from V7 sources, like make, cpp, awk, ar and more. ar needed significant rewrite because Venix uses the 'new' universal (BSD origin) header format. The final version ended up being a mix of BSD and V7 code. The others needed only small adjustments (header files mostly) in the V7 sources in order to compile using the ELKS toolchain.

Also, there are other interesting tools made available by the binary compatibility - like nroff, pic, tbl, eqn, basic (which may or may not be better than the one we already have), even Fortran (f77). Not to mention yacc, lex and the like - all of them extremely compact.

In order to make the tools useful, a host of supporting files, include files and libraries need to be moved to TLVC. These are subject to a slew of upcoming PRs - along with a strategy on how to turn it all into a working, downloadable, useable system without destroying the beauty of the basic system: Small, efficient, complete.

Finally - what's missing/not working?

  • Venix code will not work on a system without FPU, implementing soft FPU emulation is not worth it
  • Code mapping is not implemented. Basic will still run for a while, then abort as soon as the code map trap is called. VI will not even start.
  • The signal syscall will map any venix call to SIGDFL unless the request is SIGIGN, in which case it will be honoured.
  • Stack trap is not implemented. A short message like STKTRAP will be printed on the console, and the program continues. Usually, at that point there is still 128 bytes of space left on the stack which may or may not be enough. In the latter case the program will obviously crash, possibly taking the system with it. as is the primary user of the stack trap mechanism.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant