jason@mtxinu.com (Jason Venner) (03/14/89)
How is the particular cvec value determined? How does the system associate an interupt by device X with the cvex computed at autoconf time? BSD/Ultrix? Thanx -- Jason
chris@mimsy.UUCP (Chris Torek) (03/14/89)
Well, I am no fish, but ...: In article <18695@adm.BRL.MIL> kadmon!jason@mtxinu.com (Jason Venner) writes: >How is the particular cvec value determined? >How does the system associate an interupt by device X with the cvex >computed at autoconf time? > >BSD/Ultrix? As you can see by the date (1985), the instant replay below does not apply to Ultrix. (As far as I know, however, the only change is that `br' and `cvec' are global variables instead of registers, and fixctlrmask() is no more.) As for the assocation process, why, that is simplicity itself: Initially, all uba interrupts N (for N in [0.127]) vector to the N'th catcher in the sequence _catcher: pushr $0x3f # save r0,r1,r2,r3,r4,r5 jsb _Xustray # push pc and branch # these two together are exactly 8 bytes pushr $0x3f; jsb _Xustray # do it again ... repeats 126 more times ... _Xustray: blbc _cold,outta_here # error if not still configuring /* * Autoconfiguration: figure out which vector actually occurred, * and at what priority. */ mfpr $IPL,_br # or r11: interrupt level subl3 $_catcher+8,(sp)+,r0 # saved pc - catcher - 8 ashl $-1,r0,_cvec # or r10: vector (after divide by 2) popr $0x3f # restore everyone rei # and return so whatever interrupt happens is recorded. unifind() sets cvec to 01000 (0x200) and checks to make sure that, after the probe routine returns, cvec is not 01000 nor 0. (Note the `extern quad catcher[128]' at the top of unifind() in /sys/vax/autoconf.c. This was `extern int catcher[256]' in 4.2BSD; but I changed it, partly to make the compiler use movaq, but mostly to fit my twisted sense of semantics. I got lint's Locore.c edition of copyout() changed for the same reason....) And now, history repeats. . . . Date: Wed, 14 Aug 85 18:12:58 edt Newsgroups: net.unix-wizards Subject: Interrupt vectors (Re: help -- 785 won't boot) References: <177@pwa-b.UUCP> Lesson for the week on 4BSD interrupt vector assignment during autoconfiguration: Initially, in unifind(), uba_hd[uban].uh_ivec is set to 0x200 (01000; this is the first address outside of the interrupt vector space on a UBA). This basically means that on UBA adapter # uban, all the high vector addresses are unused. When a device with programmable interrupt vectors is found, its vector is chosen with the expression cvec = (uba_hd[uban].uh_ivec -= K * 4); Where uban is the index # of the UBA, and K is the number of interrupt vectors on the device. This sets cvec to the base address of K interrupt vectors on the given UBA (each one being 4 bytes wide). At the same time it decrements the uh_ivec field so that the next such device will get its vectors right below the ones just assigned. By the way, `br' and `cvec' (the magic variables in every probe routine) are `global register variables' for the duration of UBA configuration. They are not saved and restored by probe routines, due to a little routine called `fixctlrmask', which turns off the bits in the `calls' register mask that say to save r11 and r10. A device probe routine is simply supposed to verify that the device seems to be there, then attempt to cause it to interrupt. If/when it does interrupt, the handler that is invoked sets r11 and r10 based on the actual interrupt vector used by the hardware. The probe routine can simply return after the interrupt `should have happened'; unifind then looks at cvec to see if it has been set (it is reset to 0x200 before each probe); if so, br and cvec tell which interrupt vector the device actually uses, and that vector is subsequently mapped to the device's interrupt routine (through a bit of assembly code, generated automatically by /etc/config and written to ubglue.s). If the device has multiple interrupt vectors, the probe routine typically attempts to invoke the lowest-address one. If this is not convenient, one can write, e.g., /* device foo has two interrupt vectors, and we can only make it interrupt at the upper one easily: */ addr->foo_csr = FOO_IE|FOO_INT; /* cause an interrupt */ DELAY(1000); /* wait for it to happen */ if (cvec && cvec != 0x200) /* if it happened, */ cvec -= 4; /* convert cvec to the lower # */ Whenever a device has multiple interrupt vectors, autoconf expects cvec to hold the address of the `first' (numerically smallest) of these, and assigns the remainder sequentially by adding 4 each time. Autoconf can tell how many interrupt vectors there are by examining the ubdinit `ui_intr' field, which is a pointer to the first of the set of interrupt vectors; the set is terminated by a null pointer. For example, a DH, with receive and trasmit vectors, generates a list that looks like this: int (*dhint0[])() = { Xdhrint0, Xdhxint0, 0 }; (these lists are found in ioconf.c, which is generated by /etc/config based on the information found in the configuration file). One of the elements of ubdinit will then have a ui_intr field whose value is the address of `dhint0'. In particular, all of this means that there are only two places in the kernel that have any knowledge about the form of interrupt vectors for a particular device: the configuration file (which lists all the interrupt vectors in order) and the device driver (which must invoke the first of the vectors, or correct for the number of vectors between the one invoked and the first). This makes configuration of new devices relatively simple. All one needs to do is write the driver, add it to the list of `kernel source files' (conf/files and conf/files.vax), enter it into the configuration file, and build a new kernel using config and make. No assembly code need be written. (If the device is to be accessed via a character or block special device, then vax/conf.c must also be augmented as well.) ----- Next week: the potato chip driver, or how to keep your wizard properly fed during hack sessions. :-) -- In-Real-Life: Chris Torek, Univ of MD Comp Sci Dept (+1 301 454 7163) Domain: chris@mimsy.umd.edu Path: uunet!mimsy!chris