[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Re: OS calls.



>   > Line F is used on 030 machines for floating point, I think; and it's used
>   > by early TOS versions (the ones that don't run on 030's :-)) internally
>   > by the AES to call the VDI.
>   > 
>   > I would be quite surprised if the actual calling mechanism (trap vs.
>   > line A or line F) turned out to be a significant factor in system call
>   > timings. I would think that the context save/restore code would be the
>   > most significant part (at least for MiNT). Anything that we could do
>   > to speed those up, and/or to generally speed up the kernel's handling
>   > of system calls once control reaches the kernel, would be a big win.
> 
>   Well, yes. We jammed the context save/restore code on the RTU down into
>   about 20 opcodes. If we generated hardware specific kernels (68000 only,
>   68030 only, with fpu, without fpu), we could save ourselves a chunk of
>   code, and save a LOT of cycles on the Context-Switcher From Hell.
> 
>   But, yes. The use of the Line-A trap _does_ make a significant difference.
>   That's why it _is_ used for the low-level graphics primitives, rather than
>   using a spare trap.
> 
> OK. As for hardware-specific kernels - how about just jumping through a
> function pointer? Initialize the table when mint.prg starts up.

Wrapper functions perhaps, but there are distinct advantages to having
system calls operate in supervisor mode, hence the traps, and related
vectors which provide a comparitively low-overhead method of accessing
system functions.

For those calls which do not require supervisor mode operation (damn few
of them, if any), a pointer through a jump table would indeed provide a
hefty speed improvement.

On an amusing note, we discovered a bizarre way of doing virtual memory
without an MMU. We use a function, vmalloc() which returns a pointer to
invalid memory. On the plus side, it maintains a table which maps the
amount allocated to a process, and the invalid address that describes each
block. On attempting to dereference pointers to the memory, the
referencing task crashes with a bus-fault. The error handler examines the
faulting address, and ensures that the memory region required is loaded
from storage (an unknown block-device, in this case. Possibly a disk, but
in the current prototype a long-chain non-volatile serial ram buffer,
decoupled from the bus). It then grovels through the CPU registers, and
repoints any that refer to the faulting address to point to the new block.

Corollary: We had to supply a second function: vmenduse() to tell the VM
handler that none of our in-register pointers were referencing the virtual
block after that point. The region in real ram can then be saved, or
ignored, as necessary. We'd use this as register contents went out of
scope:

	global_variable=vmalloc(0x100);	/* returns invalid pointer */
	*global_variable=0;	/* Faults to the VM handler and is redirected */
	.....
	vmenduse(global_variable);	/* No longer using it within this register scope */
	return;

Second Corollary: It's a nuisance. It's slower than it could be. Any
problem at all in accessing the stored block on disk (or whatever)
completely hangs the processor. You also have to pay close attention when
coding.

Third Corollary: It's possible to switch on the presence of a VM handler,
and use normal non-virtual memory allocations, making the systteem
backwards compatible.

Is it worth the trouble? It was to us. In one case only, and we could have
worked around that with a series of wrapper functions. But we thought of
it, and implemented it, and we felt too smug and clever not to use it :)

D