Subject: Re: IRQ tables
To: Mark White <mark.white@st-edmund-hall.oxford.ac.uk>
From: Nathan J. Williams <nathanw@MIT.EDU>
List: port-i386
Date: 01/08/2001 09:10:01
<mark.white@st-edmund-hall.oxford.ac.uk> (Mark White) writes:

> Is there a way of getting a table of currently bound IRQs,
> I/O ports, & DMA channels, on a running system?  (Other than
> trawling through demsg output)
> 
> I'm thinking of /proc/ioports and friends on linux.

Not generally, no. The information is in the kernel but isn't
currently exported in a useful form. 

But attached find a little program I whipped up to read the information out
of the kernel, using the kvm interface.

Output will look something like:

56 road-runner:nathanw>./getintr
 irq  intrmask level type   (handler irq level count)...
  0   f000ffe7    2 PULSE : (c025e6f0 0 1 13533800) 
  1   f000ffc6    8  EDGE : (c010b658 1 3 15363) 
  2   10000004    0  NONE : 
  3   f000ffff    1  EDGE : (c010a034 3 0 0) 
  4   f000ffff    1  EDGE : (c010a034 4 0 1) 
  5   f000ffe6    4  EDGE : (c025b2f8 5 2 0) 
  6   d000ed44   40  EDGE : (c026a12c 6 6 1) 
  7   f000ffc6    8  EDGE : (c0259a48 7 3 0) 
  8   10000100    0  NONE : 
  9   d000ef44   20  EDGE : (c010419c 9 5 16958) 
 10   10000400    0  NONE : 
 11   10000800    0  NONE : 
 12   f000ffc6    8  EDGE : (c010b658 12 3 4246) 
 13   10002000    0  NONE : 
 14   d000ed44   40  EDGE : (c024f8b8 14 6 32068) 
 15   10008000    0  NONE : 

I was too lazy to code up the handler-address-to-function-name
translation. You can do it manually with nm and grep, as so:

58 road-runner:nathanw>nm /netbsd | grep c010419c
c010419c T epintr

Enjoy. The program is pretty kludgy; it's totally i386-specific and
tied to the current IRQ implementation, and doesn't even support
working on dead kernels (though it could, if I just copied the
relevant -N -M getopt code from ps(1) or something).

        - Nathan

# This is a shell archive.  Save it in a file, remove anything before
# this line, and then unpack it by entering "sh file".  Note, it may
# create directories; files and directories will be owned by you and
# have default permissions.
#
# This archive contains:
#
#	Makefile
#	getintr.c
#
echo x - Makefile
sed 's/^X//' >Makefile << 'END-of-Makefile'
X
XPROG=	getintr
XSRCS=	getintr.c
XDPADD=	${LIBKVM}
XLDADD=	-lkvm
X
XBINGRP=	kmem
XBINMODE=2555
X
XMAN=
X
X.include <bsd.prog.mk>
END-of-Makefile
echo x - getintr.c
sed 's/^X//' >getintr.c << 'END-of-getintr.c'
X#include <kvm.h>
X#include <stdio.h>
X#include <fcntl.h>
X#include <limits.h>
X#include <nlist.h>
X#include <sys/param.h>
X#include <sys/proc.h>
X#include "/sys/arch/i386/include/isa_machdep.h"
X
Xstruct nlist ginl[] = {
X  { "_intrhand" },
X#define X_INTRHAND 0
X  { "_intrlevel" },
X#define X_INTRLEVEL 1
X  { "_intrmask" },
X#define X_INTRMASK 2
X  { "_intrtype" },
X#define X_INTRTYPE 3
X  { NULL }
X};
X
Xchar *isa_intrtypes[] = {"NONE", "PULSE", "EDGE", "LEVEL"};
X#define kread(x, v) \
X	kvm_read(k, ginl[x].n_value, (char *)&v, sizeof v) != sizeof(v)
X
Xint main(void)
X{
X  int err, i;
X  char errstr[_POSIX2_LINE_MAX];
X  kvm_t *k;
X  void *addr;
X#define ICU_LEN 16
X  int intrtype[ICU_LEN], intrmask[ICU_LEN], intrlevel[ICU_LEN];
X  struct intrhand *intrhand[ICU_LEN];
X  struct intrhand ih;
X  k = kvm_openfiles(NULL, NULL, NULL, O_RDONLY, errstr);
X  if (k == NULL) {
X    fprintf(stderr,"kvm_openfiles: %s\n", errstr);
X    exit(1);
X  }
X
X  err = kvm_nlist(k, ginl);
X  if (err) {
X    fprintf(stderr,"kvm_nlist: %s\n", kvm_geterr(k));
X    exit(1);
X  }
X  if (kread(X_INTRLEVEL, intrlevel)) {
X    warnx("intrlevel: %s", kvm_geterr(k));
X  }
X  if (kread(X_INTRMASK, intrmask)) {
X    warnx("intrmask: %s", kvm_geterr(k));
X  }
X  if (kread(X_INTRTYPE, intrtype)) {
X    warnx("intrtype: %s", kvm_geterr(k));
X  }
X  if (kread(X_INTRHAND, intrhand)) {
X   warnx("intrhand: %s", kvm_geterr(k));
X  } 
X
X   printf(" irq  intrmask level type   (handler irq level count)...\n");
X
X  for (i = 0; i < ICU_LEN; i++) {
X    printf("%3d  %9x %4x %5s : ", i, intrmask[i], intrlevel[i], 
X	isa_intrtypes[intrtype[i]]);
X    addr = intrhand[i];
X    while (addr != NULL) {
X      err = (kvm_read(k, (u_long) addr, &ih, sizeof(ih)) != sizeof(ih));
X      if (err) {
X	warnx("intrhand[%d]: %s", i, kvm_geterr(k));
X      }
X      printf("(%x %d %d %d) ", ih.ih_fun, ih.ih_irq, ih.ih_level, ih.ih_count);
X      addr = ih.ih_next;
X    }
X    printf("\n");
X  }
X
X  err = kvm_close(k);
X  if (err) {
X    fprintf(stderr,"kvm_close: %s ", kvm_geterr(k));
X    exit(1);
X  }
X
X  return 0;
X
X}
END-of-getintr.c
exit