kend@data.UUCP (Ken Dickey) (09/26/90)
jkenton@pinocchio.encore.com (Jeff Kenton) writes: >With the recent RISC chips (88000, MIPS and i860 come to mind) the overhead >of getting the machine state safely saved away in the low level exception >code is substantial. You have to do this anyway before you can hand off >control to the user program "without going into the OS kernel", so the >savings don't amount to much. Let's talk about the next generation... There is another aspect of this which needs attention by HW implementors. There is a desire for fast computing. There is a desire for reasonable models of computation. The problem is that all traps (e.g. on the 88k) are "heavyweight" in the sense that for reasons mentioned above, OS designers don't give compiler/runtime implementors control directly. Typically, all traps get reflected through the O.S. Divide by zero and other "show stoppers" can take a long time to service, but who cares? Such exceptions reflect to a runtime handler (which may be a debugger). The real pain with heavyweight traps is trying to give reasonable performance with reasonable models. As an example, if one gets an integer numeric overflow, some languages change representations and go to bignums. It is a real pain (not to mention performance loss and code expansion) to implement the guard bits and checks almost everywhere because the runtime system can't afford the time to take a heavyweight trap. The same situation applies whether checking tagged data on polymorphic operation dispatch as in using operations on logical entities like numbers which have multiple representations. I think that the thing to concentrate on is design of HW architectures which support the above so that there are a set of "lightweight traps" which can be safely reflected to the runtime system. This could lead to a large savings in code size. I still hear "C only needs fixnums and floats, Unix only core dumps so we don't have to do better." C and Unix are in the class 20 year old technologies (circa 1972). A more general and mature view of OS and language implementation technologies than this is definitely called for. [Of course none of us would say that 8^]! -Ken Dickey kend@data.uucp
rpw3@rigden.wpd.sgi.com (Rob Warnock) (09/28/90)
In article <413@data.UUCP> kend@data.UUCP (Ken Dickey) writes: +--------------- | I think that the thing to concentrate on is design of HW architectures | which support the above so that there are a set of "lightweight traps" | which can be safely reflected to the runtime system. This could lead | to a large savings in code size. +--------------- In both of the Unix ports done to the Am29000 (S5 & BSD), the "spill/fill" assertion traps [used to shift the register window] were "trampolined" back to user mode code to perform the actual operation. In addition, a user program could request that most other (synchronous) traps also "bounce" back to a user-mode handler. The trampoline code was quite short. In the case of spill & fill, the address of the user-mode handler was kept in a kernel- protected register, thus the trampoline code was only 5 instructions: uspilltrap: mfsr tpc, PC1 ; save return address mtsr PC1, uspill ; "branch" add tav, uspill, 4 ; (sequential fetch) mtsr PC0, tav ; "branch" completely iret This was done for a couple of reasons reasons: - The copying done in a spill/fill might result in page faults or stack growth, both of which were a lot easier to handle if they came from user mode rather than from some random kernel trap handler. - You have to save/restore a dozen+ words of 29k CPU state before you can safely "come off freeze mode", which you have to do to use things like load & store multiple (which the spill/fill code wants to use!), so bouncing straight back to user mode saves all that saving/restoring. [None of that state is actually useful in the case of a synchronous trap from an "ASSERT" or "EMULATE" instruction, so nothing is "lost".] Other uses than spill/fill were found for this feature. Since in the 29k BCS different operating systems use different trap vector numbers, is was possible to write a user-mode syscall-emulation routine that could be bound with an object module from another operating system, so that system calls from that other system could be emulated under Unix by the user-mode library. Most of the compiler/assembler/tool vendors for the 29k targeted their tools for a small "operating system" (originally called "HIF", later changed to some other name -- I forgot what) that ran on an AMD prototyping board (PCEB/29k) that plugged into a PC. HIF provided a POSIX-subset interface, which was mapped to MS/DOS calls (by a program running in the PC). But the above "trampoline" feature made it possible for us to write a HIF system call emulator that was bound with the HIF object files, so we could instantly run all the PC-targeted tools under Unix! [No, nobody ever tried to emulate Sys-V under BSD or vice-versa! ;-} ] And if you want to go back *really* far, the DEC PDP-10 hardware dispatched half of the "UUO"s (Unimplemented User Operations -- trap/emulate instructions, really) to kernel mode (where they were used for system calls), and the other half directly back to the user process. Many of the compilers (especially FORTRAN) used trap-to-user UUOs to synthesize "fat instructions" which were implemented by the run-time libraries. The generated code for FORTRAN I/O was full of these things... -Rob ----- Rob Warnock, MS-9U/510 rpw3@sgi.com rpw3@pei.com Silicon Graphics, Inc. (415)335-1673 Protocol Engines, Inc. 2011 N. Shoreline Blvd. Mountain View, CA 94039-7311
jkenton@pinocchio.encore.com (Jeff Kenton) (09/28/90)
From article <70576@sgi.sgi.com>, by rpw3@rigden.wpd.sgi.com (Rob Warnock): > In article <413@data.UUCP> kend@data.UUCP (Ken Dickey) writes: > +--------------- > | I think that the thing to concentrate on is design of HW architectures > | which support the above so that there are a set of "lightweight traps" > | which can be safely reflected to the runtime system. This could lead > | to a large savings in code size. > +--------------- > > In both of the Unix ports done to the Am29000 (S5 & BSD), the "spill/fill" > assertion traps [used to shift the register window] were "trampolined" back > to user mode code to perform the actual operation. In addition, a user program > could request that most other (synchronous) traps also "bounce" back to a > user-mode handler. The trampoline code was quite short. On the 88000 this sort of fast trap is also possible, and various suppliers of 88000 boxes have made use of them (especially the real-time people). The question which started this thread, however, had to do with Herman Rubin's request for a buffer full (or was it empty) exception. This would occur under arbitrary circumstances without the need for the user code to issue any test or trap instructions (TCND or TBND on the 88000). Providing special services to user code is a lot harder when the user isn't willing to do at least a little of the work himself. ----- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - ----- ----- jeff kenton --- temporarily at jkenton@pinocchio.encore.com ----- ----- --- always at (617) 894-4508 --- ----- ----- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -----
feustel@netcom.UUCP (David Feustel) (09/29/90)
These traps could be simply implemented in the Intel 80586 by implementing a software interrupt bit vector similar to the io port permission bitmap that already exists on the 386 and 486. If the sw int bit is clear, control goes to the system when the corresponding sw int instruction is executed. Otherwise index into the first 256 pointers in low memory in the user task to get the address of the routine to be called. -- David Feustel, 1930 Curdes Ave, Fort Wayne, IN 46805, (219) 482-9631
seanf@sco.COM (Sean Fagan) (10/02/90)
In article <12824@encore.Encore.COM> jkenton@pinocchio.encore.com (Jeff Kenton) writes: >On the 88000 this sort of fast trap is also possible, and various suppliers >of 88000 boxes have made use of them (especially the real-time people). So can the '386. The question is, is it a win, in the general case, to do it, and how do you do it? I can picture a system call void (*trap) (int trapno, void (*)(int)) (int); similar to the unix signal() syscall. (Obviously, you would then set it up such that the trap would jump into user mode.) And, of course, you would have a header file (<trap.h> or <sys/trap.h>), which would define the trap numbers. You would only want to allow certain conditions to be trapped, such as overflow, divide by zero, fp exception, etc. For languages such as Ada or PL/I, which want to be able to trap these things, it would certainly be quicker (I guess 8-)) than having to go through the kernel for the trap. But I think the major speedup would be from the fact that you could make a general function, which called a function pointer, which you could change when you entered or left blocks (instead of making a system call for each exception you wish to handle). Note that I've moved this to comp.os.misc; I think it's more appropriate there (or comp.lang.misc, if it comes to that, but I think c.o.m is still correct). -- -----------------+ Sean Eric Fagan | "Never knock on Death's door: ring the bell and seanf@sco.COM | run away! Death really hates that!" uunet!sco!seanf | -- Dr. Mike Stratford (Matt Frewer, "Doctor, Doctor") (408) 458-1422 | Any opinions expressed are my own, not my employers'.