BigDumbDinosaur wrote:
On a system that is not designed to be multitasking, I agree a kernel entry jump table is less cumbersome
Sorry, I have to stop you there -- the Commodore-Amiga is a full-blown, preemptive multitasking environment which continues to utilize jump tables for OS (and non-OS) entry points. In fact, Linux modules work in a manner not
entirely dissimilar to how AmigaOS libraries work.
Just because Unix vendors in the 80s couldn't code their way out of a paper bag (I'm specifically referring to statically-linked a.out libraries and fixed-address shared libraries here (yeah, I'm talking to you SunOS and Irix!!)) doesn't mean it can't be done.
(footnote: I still think Unix vendors, including Linux coders, can't really code their way out of a paper bag. The reason is that they continue to uphold 40-year old multitasking concepts when VMS and AmigaOS both showed the world that they can do literally everything with event bits and asynchronous message queues. AmigaOS coders were multithreaded decades before the term became a household word, and wrote high-quality, (hard) real-time applications using these primitives. No, VMS and AmigaOS had to be shot down to the ground though -- we can't have any witchcraft here, NO SIR! No, you're going to have to use (shudder)
pthreads, and you'll be effin' THANKFUL!)
(another footnote: I suggest you NOT ask me how I really feel about the state of Unix and Linux today.)
Quote:
With that out of the way, the code needed to switch to kernel mode can be executed.
I disagree -- switching to kernel mode must be a hardware-level operation that occurs immediately upon executing BRK. Otherwise, you couldn't copy buffers between user space and kernel space, AND you continue to rely on the application stack, which could well be corrupted (though, you don't have a choice on the 65xx architecture).
Quote:
Doing all this would be more difficult with the jump table approach, as each entry point into the kernel would have to run the code to do what I described above.
Since there is no concept of a "kernel mode" on a 6502/65816 system without an MMU that distinguishes between processes, this really isn't a flaw.
Quote:
Code:
jsr preamble
jmp routine
Nope.
Code:
functionA:
.db 0, funcA_id, 96
functionB:
.db 0, funcB_id, 96
Of course, opcode 96 is (IIRC) RTS.
We know this approach works because of the existence proof known as "libc". Back in the day, when Unix was still running on computers with 32K of RAM or less, the Unix API and standard C library were one and the same. Today, if you examine any implementation of libc for a Unix platform, you'll find that they all basically wrap calls to INT n or SYSENTER.
Quote:
In particular, if a new OS function was added it wasn't necessary to recompile all the applications so they would know about the changed jump table.
I openly invite you to research the inner workings of the Commodore-Amiga operating system some day. AmigaOS has evolved through numerous revisions, 1.0, 1.1, 1.2, 1.3, 1.4 (not released publicly), 2.00, 2.03, 2.04, 2.05, 2.1, 2.2, 3.0, 3.1, 3.5, and the latest 3.9, and provided you didn't touch internal OS data structures, your code for 1.0 will continue to run on 3.9 (although, it'll be damn ugly).
AmigaOS libraries worked by exposing a jump table, addressed off the A6 register (we're talking the 68000 architecture here). So, if you wanted to open a file via the dos.library, for example, you'd use:
Code:
move.l _DosBase,a6
jsr _LVOOpenFile(a6)
which in turn dropped the CPU squarely on a JMP instruction to the actual code. Because the Amiga didn't statically locate any binaries
ever (you could end up with very different addresses even for many OS-level services from boot to boot), A6 provided the external linkage needed to couple two independently deployed binaries together, while the loader's relocation efforts provided internal fixups for the JMP instructions. The end result was a system that was
infinitely expandable (review the Amiga's public domain space, and you'll find out what I mean by infinitely here!), despite relying on jump tables.
So, kindly don't knock jump tables. When implemented correctly, they can work quite well.
Quote:
If he has to move the OS for any reason he's got a bit of a problem.
This is why you put the jump table at the end of ROM space, just beneath the CPU vectors. Your arguments for BRK but against jump tables is mutually inconsistent, for both jump tables and ROM vectors depend on the same environmental characteristics.