hedrick@topaz.RUTGERS.EDU (Charles Hedrick) (10/24/85)
/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); } }