/dev/kmem

Charles Hedrick hedrick at topaz.RUTGERS.EDU
Thu Oct 24 08:55:09 AEST 1985


/dev/kmem isn't "organized" at all.  It is just a window into the
kernel's address space.  You treat it like a random access file.  Do
fseek or lseek to the byte you want and read or write (*shudder*).
The trick, obviously, is to figure out which byte you want.  You have
to know where in the kernel the information you want is stored.
Generally you know a variable name in which it is stored.  So you look
it up in the symbol table ("namelist") in /vmunix, which is always
assumed to be the kernel you are currently running.  Here is a program
that changes the MTU of the first Ethernet.  (The MTU is the maximum
packet size used.)  It happens that in our kernel, the MTU is stored
at _il_softc + 6.  (As you probably know, C tends to stick _ on the
beginning of all symbols.  The name of the structure in C would be
il_softc.)  Note that this program takes two arguments: the new value,
and optionally a file to use instead of /vmunix to find the namelist.
This program was made by simplifying another one.  Thus some of its
variable and procedure names are not entirely sensible.  I have a
suspicion that the stat call is not needed.  (It is even possible that
you find this program useful for purposes other than an example.  It
should work on your system.)  When writing into the kernel, you want
to be particularly careful to get variable sizes right.  If the thing
is a short inside the kernel, you want to make sure to use a short in
your program, and to use a byte count of two for reading and writing.
Note that on the Pyramid, another way to look around inside the kernel
is by using the program "crash" with no arguments.

#include <sys/types.h>
#include <sys/stat.h>
#include <a.out.h>
#include <stdio.h>

struct nlist nl[2];

short mtu;
int kmem;
struct stat statblock;
char *kernelfile;

main(argc,argv)
char *argv[];
{
	if (argc < 2) {
		fprintf(stderr,"usage: mtu <n> {<kernelfile>}\n");
		exit(2);
	}

	if ((kmem = open("/dev/kmem",2))<0) {
		perror("open /dev/kmem");
		exit(1);
	}
	if (argc > 2) {
		kernelfile = argv[2];
	} else {
		kernelfile = "/vmunix";
	}
	if (stat(kernelfile,&statblock)) {
		fprintf(stderr,"%s not found.\n",kernelfile);
		exit(1);
	}
	initnlistvars(atoi(argv[1]));
	exit(0);
}

initnlistvars(on)
register int on;
{
	nl[0].n_un.n_name = "_il_softc";
	nl[1].n_un.n_name = "";
	nlist(kernelfile,nl);
	if (nl[0].n_type == 0) {
		fprintf(stderr, "%s: No namelist\n", kernelfile);
		exit(4);
	}
	(void) lseek(kmem,(nl[0].n_value)+6,0);
	if (read(kmem,&mtu,2) != 2) {
		perror("read kmem");
		exit(5);
	}
	fprintf(stderr,"mtu was: %d is now: %d\n",mtu,on);
	(void) lseek(kmem,(nl[0].n_value)+6,0);
	mtu = on;
	if (write(kmem,&mtu,2) != 2) {
		perror("write kmem");
		exit(6);
	}
}



More information about the Comp.unix mailing list