Path: utzoo!utgpu!jarvis.csri.toronto.edu!mailrus!tut.cis.ohio-state.edu!purdue!decwrl!shlump.dec.com!riscy.dec.com!frank From: frank@riscy.dec.com (Frank Wortner) Newsgroups: comp.unix.ultrix Subject: Re: How do you identify VAX/PMAX cpu's from software? Keywords: CPU identification Message-ID: <1243@riscy.dec.com> Date: 30 May 89 22:22:59 GMT References: <7005@cbmvax.UUCP> <105@asihub.UUCP> <1241@riscy.dec.com> <743@dinorah.wustl.edu> Reply-To: frank@croton.dec.com (Frank Wortner) Distribution: na Organization: Digital Equipment Corporation - New York ULTRIX Resource Center Lines: 377 I've cooked up a short program to identify CPUs --- just to show 1) it can be done, and 2) it is not hard. Compile the program thusly on either VAX or DECstation: cc cputype.c. Have fun! Frank ---------------------------------Cut Here------------------------------ /* * cputype.c: Print the CPU type and memory size on stdout. */ #include #include #include #include #include #include #include #include #include #ifdef vax # include #endif #ifdef mips # include #endif /* * The kernal data structures we are interested in. */ struct nlist namelist[] = { /* * Names of things and other "static" data. */ { "_physmem" }, /* NM_PHYSMEM */ { "_cpu" }, /* NM_CPU */ { "_cpudata" }, /* NM_CPUDATA */ { "_cpu_subtype" }, /* NM_CPU_SUBTYPE */ /* * This will only be used by the MIPS based systems, * but it doesn't need to be #ifdef'd. */ { "_cpu_systype" }, /* NM_CPU_SYSTYPE */ /* * End of list. */ { 0 } }; #define NM_PHYSMEM 0 #define NM_CPU 1 #define NM_CPUDATA 2 #define NM_CPU_SUBTYPE 3 #define NM_CPU_SYSTYPE 4 /* * These arrays will allow cpu.c to get a CPU string from * a type and subtype. */ struct cpu_type { int type; char *string; struct cpu_type *subtype; }; #ifdef vax struct cpu_type vax8200[] = { ST_8200, "VAX 8200/8250", NULL, ST_8300, "VAX 8300/8350", NULL, ST_8400, "VAX 8400/8450", NULL, { 0, 0, 0, }, }; struct cpu_type vax8800[] = { ST_8500, "VAX 8500/8530", NULL, ST_8550, "VAX 8550", NULL, ST_8700, "VAX 8700", NULL, ST_8800, "VAX 8800", NULL, { 0, 0, 0, }, }; struct cpu_type microvax2[] = { ST_MVAXII, "MicroVAX/VAXstation II", NULL, ST_VAXSTAR, "MicroVAX/VAXstation 2000", NULL, { 0, 0, 0, }, }; struct cpu_type cpu_types[] = { /* * The VAX list. */ VAX_780, "VAX 11/780 or 11/785", NULL, VAX_750, "VAX 11/750 or 11/751", NULL, VAX_730, "VAX 11/730 or 11/725", NULL, VAX_8600, "VAX 8600/8650", NULL, VAX_8200, "VAX 8200/8250/8300/8350", vax8200, VAX_8800, "VAX 8800/8700/8550/8530/8500", vax8800, MVAX_I, "MicroVAX I", NULL, MVAX_II, "MicroVAX/VAXstation II", microvax2, /* * Future CPU types will need to be #ifdef'd as these * are. This lets the data be updated for newer versions * but still be backward compatiable. */ #ifdef C_VAX C_VAX, "MicroVAX/VAXstation 3200/3500/3600", NULL, #endif #ifdef VAX_6200 VAX_6200, "VAX 6210/6220/6230/6240", NULL, #endif #ifdef C_VAXSTAR C_VAXSTAR, "VAXstation 3100", NULL, #endif #ifdef VAX_8820 VAX_8820, "VAX 8820/8830/8840", NULL, #endif }; #endif /* * The MIPS list. */ #ifdef mips struct cpu_type cpu_types[] = { { PMAX, "DECstation 3100", NULL, }, { 0, 0, 0, }, } ; #endif static int kmem; /* * Functions which don't return (int). */ char *str_cpuid(); void nlist(), fatal(), readk(); main() { cpu_names(); exit (0); } /* * Print something about the CPU. */ static cpu_names() { int sid, physmem ; long subtype = -1 ; caddr_t addr ; sid = getsid() ; /* * Get the amount of physical memory. */ if((addr = (caddr_t)namelist[NM_PHYSMEM].n_value) == 0 ) { warning("Can't get physical memory size.\n") ; return ; } else readk((long)addr, (char *)&physmem, sizeof(physmem)) ; #ifdef vax subtype = get_cpu_subtype(addr); #endif #ifdef mips subtype = GETCPUTYPE(sid) ; #endif printf("%s with %d bytes of memory.\n", str_cpuid(sid, subtype), physmem * NBPG) ; } /* * Local version of a system call to get the contents of the SID * register. This function constructs a number which looks like * the contents of a CPU SID register. * * It is a feature of the MicroVAX architecture that this function * will always return the correct SID. */ getsid() { /* * Data for the two architectures. */ #ifdef vax int nm_cpu ; union cpusid cpu ; #endif #ifdef mips int cpu_systype ; #endif open_names(); /* * The architecture dependent code. */ #ifdef vax readk((long)namelist[NM_CPU].n_value, (char *)&nm_cpu, sizeof(nm_cpu)) ; cpu.cpuany.cp_type = nm_cpu ; return cpu.cpusid ; #endif #ifdef mips readk((long)namelist[NM_CPU_SYSTYPE].n_value, (char *)&cpu_systype, sizeof(cpu_systype)) ; return cpu_systype ; #endif } /* * Set up the namelist and open the kernel so we can get * to the names. */ open_names(op) { /* * Initialize the namelist, nlist(x) doesn't return * anything to signify an error. */ (void)nlist("/vmunix", namelist) ; /* * Open memory. */ if((kmem = open("/dev/kmem", O_RDONLY, 0)) == -1 ) fatal("Can't open /dev/kmem: ") ; } /* * Try to close /dev/kmem. */ close_names(op) { if( close(kmem) == -1 ) fatal("Can't close /dev/kmem: ") ; } /* * Get the CPU subtype. */ int get_cpu_subtype(addr) caddr_t addr; { int subtype; if((addr = (caddr_t)namelist[NM_CPU_SUBTYPE].n_value) == 0 ) subtype = -1 ; else readk((long)addr, (char *)&subtype, sizeof(long)) ; return (subtype); } /* * Seek to "where" in the kernel and read "size" bytes * into the space at "addr". */ void readk(where, addr, size) long where ; char *addr ; int size ; { long lseek() ; if( lseek(kmem, where, L_SET) == -1 ) fatal("Can't lseek in /dev/kmem: "); if( read(kmem, addr, size) == -1 ) fatal("Can't read from /dev/kmem: "); } /* * Functions and data to take the CPU id and turn it into something * "meaningful". */ char *str_cpuid(ident, subtype) int ident ; long subtype ; { #ifdef vax union cpusid cpu ; #endif int type ; struct cpu_type *sp, *tp ; tp = &cpu_types[0] ; /* * This is the VAX version of how to turn the system * id into a system name. */ #ifdef vax cpu.cpusid = ident ; type = cpu.cpuany.cp_type ; #endif /* * On the mips we can get everything from the cpu_systype. */ #ifdef mips type = GETSYSTYPE(ident) ; #endif while( tp->string != NULL ) { if( tp->type == type ) { /* * If there isn't a subtype list return * the string for the type. */ if((sp = tp->subtype) == NULL ) return tp->string ; /* * Else... Walk the the subtype list * looking for a matching subtype. */ while( sp->string != NULL ) { if( sp->type == subtype ) return sp->string ; sp++ ; } /* * If there isn't a subtype match return * the type string. */ return tp->string ; } tp++ ; } return "Unknown CPU type" ; } void fatal(str) char *str; { perror(str); exit(1); } warning(str) { fprintf(stderr, "%s\n", str); }