diff options
Diffstat (limited to 'perl-install/c')
-rw-r--r-- | perl-install/c/Makefile.PL | 1 | ||||
-rw-r--r-- | perl-install/c/smp.c | 342 | ||||
-rw-r--r-- | perl-install/c/stuff.xs.pm | 3 |
3 files changed, 346 insertions, 0 deletions
diff --git a/perl-install/c/Makefile.PL b/perl-install/c/Makefile.PL index 647d5bcc0..a8d6df7b8 100644 --- a/perl-install/c/Makefile.PL +++ b/perl-install/c/Makefile.PL @@ -10,6 +10,7 @@ WriteMakefile( 'NAME' => 'stuff', 'OPTIMIZE' => '-Os', 'MAKEFILE' => 'Makefile_c', + 'OBJECT' => 'stuff.o smp.o', 'VERSION_FROM' => 'stuff.pm', # finds $VERSION 'LIBS' => [$libs], # e.g., '-lm' 'DEFINE' => '', # e.g., '-DHAVE_SOMETHING' diff --git a/perl-install/c/smp.c b/perl-install/c/smp.c new file mode 100644 index 000000000..08b2b0a7c --- /dev/null +++ b/perl-install/c/smp.c @@ -0,0 +1,342 @@ +/* +[_Anarchy_(alan@lightning.swansea.uk.linux.org)] you should do one check + though - if the board seems to be SMP and the CPU in /proc/cpuinfo is non + intel dont install an SMP kernel - thats a dual pentium board with a cyrix + or similar single cpu in it +*/ + + +#include <stdio.h> +#include <stdlib.h> +#include <unistd.h> +#include <fcntl.h> +#include <sys/mman.h> +#include <string.h> +#include <errno.h> + +#ifdef __alpha__ +int alphaDetectSMP(void) +{ + int issmp = 0; + FILE *f; + + f = fopen("/proc/cpuinfo", "r"); + if (f) { + char buff[1024]; + + while (fgets (buff, 1024, f) != NULL) { + if (!strncmp (buff, "cpus detected\t\t: ", 17)) { + if (strtoul (buff + 17, NULL, 0) > 1) + issmp = 1; + break; + } + } + fclose(f); + } else + return -1; + + return issmp; +} +#endif /* __alpha__ */ + +#ifdef __sparc__ +int sparcDetectSMP(void) +{ + int issmp = 0; + FILE *f; + + f = fopen("/proc/cpuinfo", "r"); + if (f) { + char buff[1024]; + + while (fgets (buff, 1024, f) != NULL) { + if (!strncmp (buff, "ncpus active\t: ", 15)) { + if (strtoul (buff + 15, NULL, 0) > 1) + issmp = 1; + break; + } + } + fclose(f); + } else + return -1; + + return issmp; +} +#endif /* __sparc__ */ + +#ifdef __i386__ +#define SMP_MAGIC_IDENT (('_'<<24)|('P'<<16)|('M'<<8)|'_') + +struct intel_mp_floating +{ + char mpf_signature[4]; /* "_MP_" */ + unsigned long mpf_physptr; /* Configuration table address */ + unsigned char mpf_length; /* Our length (paragraphs) */ + unsigned char mpf_specification;/* Specification version */ + unsigned char mpf_checksum; /* Checksum (makes sum 0) */ + unsigned char mpf_feature1; /* Standard or configuration ? */ + unsigned char mpf_feature2; /* Bit7 set for IMCR|PIC */ + unsigned char mpf_feature3; /* Unused (0) */ + unsigned char mpf_feature4; /* Unused (0) */ + unsigned char mpf_feature5; /* Unused (0) */ +}; + +struct mp_config_table +{ + char mpc_signature[4]; +#define MPC_SIGNATURE "PCMP" + unsigned short mpc_length; /* Size of table */ + char mpc_spec; /* 0x01 */ + char mpc_checksum; + char mpc_oem[8]; + char mpc_productid[12]; + unsigned long mpc_oemptr; /* 0 if not present */ + unsigned short mpc_oemsize; /* 0 if not present */ + unsigned short mpc_oemcount; + unsigned long mpc_lapic; /* APIC address */ + unsigned long reserved; +}; + +/* Followed by entries */ + +#define MP_PROCESSOR 0 +#define MP_BUS 1 +#define MP_IOAPIC 2 +#define MP_INTSRC 3 +#define MP_LINTSRC 4 + +struct mpc_config_processor +{ + unsigned char mpc_type; + unsigned char mpc_apicid; /* Local APIC number */ + unsigned char mpc_apicver; /* Its versions */ + unsigned char mpc_cpuflag; +#define CPU_ENABLED 1 /* Processor is available */ +#define CPU_BOOTPROCESSOR 2 /* Processor is the BP */ + unsigned long mpc_cpufeature; +#define CPU_STEPPING_MASK 0x0F +#define CPU_MODEL_MASK 0xF0 +#define CPU_FAMILY_MASK 0xF00 + unsigned long mpc_featureflag; /* CPUID feature value */ + unsigned long mpc_reserved[2]; +}; + +struct mpc_config_bus +{ + unsigned char mpc_type; + unsigned char mpc_busid; + unsigned char mpc_bustype[6] __attribute((packed)); +}; + +#define BUSTYPE_EISA "EISA" +#define BUSTYPE_ISA "ISA" +#define BUSTYPE_INTERN "INTERN" /* Internal BUS */ +#define BUSTYPE_MCA "MCA" +#define BUSTYPE_VL "VL" /* Local bus */ +#define BUSTYPE_PCI "PCI" +#define BUSTYPE_PCMCIA "PCMCIA" + +/* We don't understand the others */ + +struct mpc_config_ioapic +{ + unsigned char mpc_type; + unsigned char mpc_apicid; + unsigned char mpc_apicver; + unsigned char mpc_flags; +#define MPC_APIC_USABLE 0x01 + unsigned long mpc_apicaddr; +}; + +struct mpc_config_intsrc +{ + unsigned char mpc_type; + unsigned char mpc_irqtype; + unsigned short mpc_irqflag; + unsigned char mpc_srcbus; + unsigned char mpc_srcbusirq; + unsigned char mpc_dstapic; + unsigned char mpc_dstirq; +}; + +#define MP_INT_VECTORED 0 +#define MP_INT_NMI 1 +#define MP_INT_SMI 2 +#define MP_INT_EXTINT 3 + +#define MP_IRQDIR_DEFAULT 0 +#define MP_IRQDIR_HIGH 1 +#define MP_IRQDIR_LOW 3 + + +struct mpc_config_intlocal +{ + unsigned char mpc_type; + unsigned char mpc_irqtype; + unsigned short mpc_irqflag; + unsigned char mpc_srcbusid; + unsigned char mpc_srcbusirq; + unsigned char mpc_destapic; +#define MP_APIC_ALL 0xFF + unsigned char mpc_destapiclint; +}; + + +/* + * Default configurations + * + * 1 2 CPU ISA 82489DX + * 2 2 CPU EISA 82489DX no IRQ 8 or timer chaining + * 3 2 CPU EISA 82489DX + * 4 2 CPU MCA 82489DX + * 5 2 CPU ISA+PCI + * 6 2 CPU EISA+PCI + * 7 2 CPU MCA+PCI + */ + + +static int smp_found_config=0; + +/* + * Checksum an MP configuration block. + */ + +static int mpf_checksum(unsigned char *mp, int len) +{ + int sum=0; + while(len--) + sum+=*mp++; + return sum&0xFF; +} + +static int do_smp_scan_config(unsigned long *bp, unsigned long length) +{ + struct intel_mp_floating *mpf; + +/* + if (sizeof(*mpf)!=16) + logMessage("Error: MPF size\n"); +*/ + + while (length>0) + { + if (*bp==SMP_MAGIC_IDENT) + { + mpf=(struct intel_mp_floating *)bp; + if (mpf->mpf_length==1 && + !mpf_checksum((unsigned char *)bp,16) && + (mpf->mpf_specification == 1 + || mpf->mpf_specification == 4) ) + { + /*logMessage("Intel MultiProcessor Specification v1.%d\n", mpf->mpf_specification); + if (mpf->mpf_feature2&(1<<7)) + logMessage(" IMCR and PIC compatibility mode.\n"); + else + logMessage(" Virtual Wire compatibility mode.\n"); +*/ + smp_found_config=1; + return 1; + } + } + bp+=4; + length-=16; + } + + return 0; +} + +static int smp_scan_config(int mem_fd, unsigned long base, + unsigned long length) +{ + void *p; + int o; + + o=base&0xFFF; + base-=o; + length+=o; + + p=mmap(0, (length+4095)&0xFFFFF000, PROT_READ, MAP_SHARED, + mem_fd, (base&0xFFFF0000)); + if(p==MAP_FAILED) + { + /*logMessage("SMP Probe error: mmap: %s", strerror(errno));*/ + return 1; + } + do_smp_scan_config(p+o, length-o); + munmap(p, (length+4095)&0xFFFFF000); + return 0; +} + +static int intelDetectSMP(void) +{ + int mem_fd; + + mem_fd=open("/dev/mem", O_RDONLY); + + if(mem_fd==-1) + { + /*logMessage("Error detecting SMP: /dev/mem: %s", strerror(errno));*/ + } + + /* + * FIXME: Linux assumes you have 640K of base ram.. + * this continues the error... + * + * 1) Scan the bottom 1K for a signature + * 2) Scan the top 1K of base RAM + * 3) Scan the 64K of bios + */ + if (!smp_scan_config(mem_fd, 0x0, 0x400) && + !smp_scan_config(mem_fd, 639*0x400,0x400) && + !smp_scan_config(mem_fd, 0xF0000,0x10000)) { +#if 0 + + /* + * If it is an SMP machine we should know now, unless the + * configuration is in an EISA/MCA bus machine with an + * extended bios data area. + * + * there is a real-mode segmented pointer pointing to the + * 4K EBDA area at 0x40E, calculate and scan it here. + * + * NOTE! There are Linux loaders that will corrupt the EBDA + * area, and as such this kind of SMP config may be less + * trustworthy, simply because the SMP table may have been + * stomped on during early boot. These loaders are buggy and + * should be fixed. + */ + unsigned int address; + + address = *(unsigned short *)phys_to_virt(0x40E); + address<<=4; + smp_scan_config(mem_fd, address, 0x1000); + if (smp_found_config) + /*logMessage("WARNING: MP table in the EBDA can be UNSAFE, contact linux-smp@vger.rutgers.edu if you experience SMP problems!\n");*/ +#endif + } +/* + if(smp_found_config) + logMessage("Detected SMP capable motherboard\n"); + else + logMessage("Detected non SMP capable motherboard\n"); +*/ + return smp_found_config; +} +#endif /* __i386__ */ + +int detectSMP(void) +{ + static int isSMP = -1; + + if (isSMP != -1) + return isSMP; + +#ifdef __i386__ + return isSMP = intelDetectSMP(); +#elif __sparc__ + return isSMP = sparcDetectSMP(); +#elif __alpha__ + return isSMP = alphaDetectSMP(); +#endif +} + diff --git a/perl-install/c/stuff.xs.pm b/perl-install/c/stuff.xs.pm index 12bdc913c..db07893a1 100644 --- a/perl-install/c/stuff.xs.pm +++ b/perl-install/c/stuff.xs.pm @@ -106,6 +106,9 @@ lseek_sector(fd, sector, offset) void setsid() +int +detectSMP() + unsigned int getpagesize() |