summaryrefslogtreecommitdiffstats
path: root/tools
diff options
context:
space:
mode:
authorsam <sam@FreeBSD.org>2006-02-22 21:51:09 +0000
committersam <sam@FreeBSD.org>2006-02-22 21:51:09 +0000
commitd1c19fee82e05ef84e395174a252e26cea5a068e (patch)
treeb43bec7d2469d578a89529415784956017e9d957 /tools
parentc4fac66722dfcac09c40ba59465af01664edd226 (diff)
downloadFreeBSD-src-d1c19fee82e05ef84e395174a252e26cea5a068e.zip
FreeBSD-src-d1c19fee82e05ef84e395174a252e26cea5a068e.tar.gz
test program to check cpu counting
MFC after: 1 week
Diffstat (limited to 'tools')
-rw-r--r--tools/tools/README1
-rw-r--r--tools/tools/ncpus/Makefile11
-rw-r--r--tools/tools/ncpus/acpi.c335
-rw-r--r--tools/tools/ncpus/acpidump.h177
-rw-r--r--tools/tools/ncpus/biosmptable.c265
-rw-r--r--tools/tools/ncpus/ncpus.c14
6 files changed, 803 insertions, 0 deletions
diff --git a/tools/tools/README b/tools/tools/README
index ddb3389..a0a6ee9 100644
--- a/tools/tools/README
+++ b/tools/tools/README
@@ -41,6 +41,7 @@ kttcp An in-kernel version of the ttcp network performance tool
mfc Merge a directory from HEAD to a branch where it does not
already exist and other MFC related script(s).
mid Create a Message-ID database for mailing lists.
+ncpus Count the number of processors
pciid Generate src/share/misc/pci_vendors.
pirtool A tool for dumping the $PIR table on i386 machines at runtime.
portsinfo Generate list of new ports for last two weeks.
diff --git a/tools/tools/ncpus/Makefile b/tools/tools/ncpus/Makefile
new file mode 100644
index 0000000..7d2410c
--- /dev/null
+++ b/tools/tools/ncpus/Makefile
@@ -0,0 +1,11 @@
+# $FreeBSD$
+
+PROG= ncpus
+SRCS= ncpus.c acpi.c biosmptable.c
+NO_MAN= noman
+BINDIR= /usr/local/bin
+
+DPADD= ${LIBDEVINFO}
+LDADD= -ldevinfo
+
+.include <bsd.prog.mk>
diff --git a/tools/tools/ncpus/acpi.c b/tools/tools/ncpus/acpi.c
new file mode 100644
index 0000000..2cdf637
--- /dev/null
+++ b/tools/tools/ncpus/acpi.c
@@ -0,0 +1,335 @@
+/*-
+ * Copyright (c) 1998 Doug Rabson
+ * Copyright (c) 2000 Mitsuru IWASAKI <iwasaki@FreeBSD.org>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $FreeBSD$
+ */
+
+#include <sys/param.h>
+#include <sys/endian.h>
+#include <sys/mman.h>
+#include <sys/queue.h>
+#include <sys/stat.h>
+#include <sys/sysctl.h>
+#include <sys/wait.h>
+#include <assert.h>
+#include <err.h>
+#include <fcntl.h>
+#include <stdio.h>
+#include <string.h>
+#include <unistd.h>
+#include <paths.h>
+#include <devinfo.h>
+
+#include "acpidump.h"
+
+static void acpi_handle_apic(struct ACPIsdt *sdp);
+static struct ACPIsdt *acpi_map_sdt(vm_offset_t pa);
+static void acpi_handle_rsdt(struct ACPIsdt *rsdp);
+static struct acpi_user_mapping *acpi_user_find_mapping(vm_offset_t, size_t);
+static void * acpi_map_physical(vm_offset_t, size_t);
+
+/* Size of an address. 32-bit for ACPI 1.0, 64-bit for ACPI 2.0 and up. */
+static int addr_size;
+
+static int ncpu;
+
+static int
+max(int a, int b)
+{
+ return a < b ? b : a;
+}
+
+static void
+acpi_handle_apic(struct ACPIsdt *sdp)
+{
+ struct MADTbody *madtp;
+ struct MADT_APIC *mp;
+ struct MADT_local_apic *apic;
+ struct MADT_local_sapic *sapic;
+
+ madtp = (struct MADTbody *) sdp->body;
+ mp = (struct MADT_APIC *)madtp->body;
+ while (((uintptr_t)mp) - ((uintptr_t)sdp) < sdp->len) {
+ switch (mp->type) {
+ case ACPI_MADT_APIC_TYPE_LOCAL_APIC:
+ apic = &mp->body.local_apic;
+ warnx("MADT: Found CPU APIC ID %d %s",
+ apic->cpu_id,
+ apic->flags & ACPI_MADT_APIC_LOCAL_FLAG_ENABLED ?
+ "enabled" : "disabled");
+ if (apic->flags & ACPI_MADT_APIC_LOCAL_FLAG_ENABLED)
+ ncpu++;
+ break;
+ case ACPI_MADT_APIC_TYPE_LOCAL_SAPIC:
+ sapic = &mp->body.local_sapic;
+ warnx("MADT: Found CPU SAPIC ID %d %s",
+ sapic->cpu_id,
+ sapic->flags & ACPI_MADT_APIC_LOCAL_FLAG_ENABLED ?
+ "enabled" : "disabled");
+ /* XXX is enable flag the same? */
+ if (sapic->flags & ACPI_MADT_APIC_LOCAL_FLAG_ENABLED)
+ ncpu++;
+ break;
+ default:
+ break;
+ }
+ mp = (struct MADT_APIC *) ((char *)mp + mp->len);
+ }
+}
+
+static int
+acpi_checksum(void *p, size_t length)
+{
+ u_int8_t *bp;
+ u_int8_t sum;
+
+ bp = p;
+ sum = 0;
+ while (length--)
+ sum += *bp++;
+
+ return (sum);
+}
+
+static struct ACPIsdt *
+acpi_map_sdt(vm_offset_t pa)
+{
+ struct ACPIsdt *sp;
+
+ sp = acpi_map_physical(pa, sizeof(struct ACPIsdt));
+ sp = acpi_map_physical(pa, sp->len);
+ return (sp);
+}
+
+static void
+acpi_handle_rsdt(struct ACPIsdt *rsdp)
+{
+ struct ACPIsdt *sdp;
+ vm_offset_t addr;
+ int entries, i;
+
+ entries = (rsdp->len - SIZEOF_SDT_HDR) / addr_size;
+ for (i = 0; i < entries; i++) {
+ switch (addr_size) {
+ case 4:
+ addr = le32dec((char*)rsdp->body + i * addr_size);
+ break;
+ case 8:
+ addr = le64dec((char*)rsdp->body + i * addr_size);
+ break;
+ default:
+ assert((addr = 0));
+ }
+
+ sdp = (struct ACPIsdt *)acpi_map_sdt(addr);
+ if (acpi_checksum(sdp, sdp->len)) {
+#if 0
+ warnx("RSDT entry %d (sig %.4s) has bad checksum", i,
+ sdp->signature);
+#endif
+ continue;
+ }
+ if (!memcmp(sdp->signature, "APIC", 4))
+ acpi_handle_apic(sdp);
+ }
+}
+
+static char machdep_acpi_root[] = "machdep.acpi_root";
+static int acpi_mem_fd = -1;
+
+struct acpi_user_mapping {
+ LIST_ENTRY(acpi_user_mapping) link;
+ vm_offset_t pa;
+ caddr_t va;
+ size_t size;
+};
+
+LIST_HEAD(acpi_user_mapping_list, acpi_user_mapping) maplist;
+
+static void
+acpi_user_init(void)
+{
+
+ if (acpi_mem_fd == -1) {
+ acpi_mem_fd = open(_PATH_MEM, O_RDONLY);
+ if (acpi_mem_fd == -1)
+ err(1, "opening " _PATH_MEM);
+ LIST_INIT(&maplist);
+ }
+}
+
+static struct acpi_user_mapping *
+acpi_user_find_mapping(vm_offset_t pa, size_t size)
+{
+ struct acpi_user_mapping *map;
+
+ /* First search for an existing mapping */
+ for (map = LIST_FIRST(&maplist); map; map = LIST_NEXT(map, link)) {
+ if (map->pa <= pa && map->size >= pa + size - map->pa)
+ return (map);
+ }
+
+ /* Then create a new one */
+ size = round_page(pa + size) - trunc_page(pa);
+ pa = trunc_page(pa);
+ map = malloc(sizeof(struct acpi_user_mapping));
+ if (!map)
+ errx(1, "out of memory");
+ map->pa = pa;
+ map->va = mmap(0, size, PROT_READ, MAP_SHARED, acpi_mem_fd, pa);
+ map->size = size;
+ if ((intptr_t) map->va == -1)
+ err(1, "can't map address");
+ LIST_INSERT_HEAD(&maplist, map, link);
+
+ return (map);
+}
+
+static void *
+acpi_map_physical(vm_offset_t pa, size_t size)
+{
+ struct acpi_user_mapping *map;
+
+ map = acpi_user_find_mapping(pa, size);
+ return (map->va + (pa - map->pa));
+}
+
+static struct ACPIrsdp *
+acpi_get_rsdp(u_long addr)
+{
+ struct ACPIrsdp rsdp;
+ size_t len;
+
+ /* Read in the table signature and check it. */
+ pread(acpi_mem_fd, &rsdp, 8, addr);
+ if (memcmp(rsdp.signature, "RSD PTR ", 8))
+ return (NULL);
+
+ /* Read the entire table. */
+ pread(acpi_mem_fd, &rsdp, sizeof(rsdp), addr);
+
+ /* Run the checksum only over the version 1 header. */
+ if (acpi_checksum(&rsdp, 20))
+ return (NULL);
+
+ /* If the revision is 0, assume a version 1 length. */
+ if (rsdp.revision == 0)
+ len = 20;
+ else
+ len = rsdp.length;
+
+ /* XXX Should handle ACPI 2.0 RSDP extended checksum here. */
+
+ return (acpi_map_physical(addr, len));
+}
+
+static const char *
+devstate(devinfo_state_t state)
+{
+ switch (state) {
+ case DIS_NOTPRESENT:
+ return "not-present";
+ case DIS_ALIVE:
+ return "alive";
+ case DIS_ATTACHED:
+ return "attached";
+ case DIS_BUSY:
+ return "busy";
+ default:
+ return "unknown-state";
+ }
+}
+
+static int
+acpi0_check(struct devinfo_dev *dd, void *arg)
+{
+ printf("%s: %s %s\n", __func__, dd->dd_name, devstate(dd->dd_state));
+ /* NB: device must be present AND attached */
+ if (strcmp(dd->dd_name, "acpi0") == 0)
+ return (dd->dd_state == DIS_ATTACHED ||
+ dd->dd_state == DIS_BUSY);
+ return devinfo_foreach_device_child(dd, acpi0_check, arg);
+}
+
+static int
+acpi0_present(void)
+{
+ struct devinfo_dev *root;
+ int found;
+
+ found = 0;
+ devinfo_init();
+ root = devinfo_handle_to_device(DEVINFO_ROOT_DEVICE);
+ if (root != NULL)
+ found = devinfo_foreach_device_child(root, acpi0_check, NULL);
+ devinfo_free();
+ return found;
+}
+
+int
+acpi_detect(void)
+{
+ struct ACPIrsdp *rp;
+ struct ACPIsdt *rsdp;
+ u_long addr;
+ size_t len;
+
+ if (!acpi0_present()) {
+ warnx("no acpi0 device located");
+ return -1;
+ }
+
+ acpi_user_init();
+
+ /* Attempt to use sysctl to find RSD PTR record. */
+ len = sizeof(addr);
+ if (sysctlbyname(machdep_acpi_root, &addr, &len, NULL, 0) != 0) {
+ warnx("cannot find ACPI information");
+ return -1;
+ }
+ rp = acpi_get_rsdp(addr);
+ if (rp == NULL) {
+ warnx("cannot find ACPI information: sysctl %s does not point to RSDP",
+ machdep_acpi_root);
+ return -1;
+ }
+ if (rp->revision < 2) {
+ rsdp = (struct ACPIsdt *)acpi_map_sdt(rp->rsdt_addr);
+ if (memcmp(rsdp->signature, "RSDT", 4) != 0 ||
+ acpi_checksum(rsdp, rsdp->len) != 0)
+ errx(1, "RSDT is corrupted");
+ addr_size = sizeof(uint32_t);
+ } else {
+ rsdp = (struct ACPIsdt *)acpi_map_sdt(rp->xsdt_addr);
+ if (memcmp(rsdp->signature, "XSDT", 4) != 0 ||
+ acpi_checksum(rsdp, rsdp->len) != 0)
+ errx(1, "XSDT is corrupted");
+ addr_size = sizeof(uint64_t);
+ }
+ ncpu = 0;
+ acpi_handle_rsdt(rsdp);
+ return (ncpu);
+}
diff --git a/tools/tools/ncpus/acpidump.h b/tools/tools/ncpus/acpidump.h
new file mode 100644
index 0000000..9c2b5b6
--- /dev/null
+++ b/tools/tools/ncpus/acpidump.h
@@ -0,0 +1,177 @@
+/*-
+ * Copyright (c) 1999 Doug Rabson
+ * Copyright (c) 2000 Mitsuru IWASAKI <iwasaki@FreeBSD.org>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $FreeBSD$
+ */
+
+#ifndef _ACPIDUMP_H_
+#define _ACPIDUMP_H_
+
+/* Root System Description Pointer */
+struct ACPIrsdp {
+ u_char signature[8];
+ u_char sum;
+ u_char oem[6];
+ u_char revision;
+ u_int32_t rsdt_addr;
+ u_int32_t length;
+ u_int64_t xsdt_addr;
+ u_char xsum;
+ u_char _reserved_[3];
+} __packed;
+
+/* System Description Table */
+struct ACPIsdt {
+ u_char signature[4];
+ u_int32_t len;
+ u_char rev;
+ u_char check;
+ u_char oemid[6];
+ u_char oemtblid[8];
+ u_int32_t oemrev;
+ u_char creator[4];
+ u_int32_t crerev;
+#define SIZEOF_SDT_HDR 36 /* struct size except body */
+ u_int32_t body[1];/* This member should be casted */
+} __packed;
+
+struct MADT_local_apic {
+ u_char cpu_id;
+ u_char apic_id;
+ u_int32_t flags;
+#define ACPI_MADT_APIC_LOCAL_FLAG_ENABLED 1
+} __packed;
+
+struct MADT_io_apic {
+ u_char apic_id;
+ u_char reserved;
+ u_int32_t apic_addr;
+ u_int32_t int_base;
+} __packed;
+
+struct MADT_int_override {
+ u_char bus;
+ u_char source;
+ u_int32_t intr;
+ u_int16_t mps_flags;
+#define MPS_INT_FLAG_POLARITY_MASK 0x3
+#define MPS_INT_FLAG_POLARITY_CONFORM 0x0
+#define MPS_INT_FLAG_POLARITY_HIGH 0x1
+#define MPS_INT_FLAG_POLARITY_LOW 0x3
+#define MPS_INT_FLAG_TRIGGER_MASK 0xc
+#define MPS_INT_FLAG_TRIGGER_CONFORM 0x0
+#define MPS_INT_FLAG_TRIGGER_EDGE 0x4
+#define MPS_INT_FLAG_TRIGGER_LEVEL 0xc
+} __packed;
+
+struct MADT_nmi {
+ u_int16_t mps_flags;
+ u_int32_t intr;
+} __packed;
+
+struct MADT_local_nmi {
+ u_char cpu_id;
+ u_int16_t mps_flags;
+ u_char lintpin;
+} __packed;
+
+struct MADT_local_apic_override {
+ u_char reserved[2];
+ u_int64_t apic_addr;
+} __packed;
+
+struct MADT_io_sapic {
+ u_char apic_id;
+ u_char reserved;
+ u_int32_t int_base;
+ u_int64_t apic_addr;
+} __packed;
+
+struct MADT_local_sapic {
+ u_char cpu_id;
+ u_char apic_id;
+ u_char apic_eid;
+ u_char reserved[3];
+ u_int32_t flags;
+} __packed;
+
+struct MADT_int_src {
+ u_int16_t mps_flags;
+ u_char type;
+#define ACPI_MADT_APIC_INT_SOURCE_PMI 1
+#define ACPI_MADT_APIC_INT_SOURCE_INIT 2
+#define ACPI_MADT_APIC_INT_SOURCE_CPEI 3 /* Corrected Platform Error */
+ u_char cpu_id;
+ u_char cpu_eid;
+ u_char sapic_vector;
+ u_int32_t intr;
+ u_char reserved[4];
+} __packed;
+
+struct MADT_APIC {
+ u_char type;
+#define ACPI_MADT_APIC_TYPE_LOCAL_APIC 0
+#define ACPI_MADT_APIC_TYPE_IO_APIC 1
+#define ACPI_MADT_APIC_TYPE_INT_OVERRIDE 2
+#define ACPI_MADT_APIC_TYPE_NMI 3
+#define ACPI_MADT_APIC_TYPE_LOCAL_NMI 4
+#define ACPI_MADT_APIC_TYPE_LOCAL_OVERRIDE 5
+#define ACPI_MADT_APIC_TYPE_IO_SAPIC 6
+#define ACPI_MADT_APIC_TYPE_LOCAL_SAPIC 7
+#define ACPI_MADT_APIC_TYPE_INT_SRC 8
+ u_char len;
+ union {
+ struct MADT_local_apic local_apic;
+ struct MADT_io_apic io_apic;
+ struct MADT_int_override int_override;
+ struct MADT_nmi nmi;
+ struct MADT_local_nmi local_nmi;
+ struct MADT_local_apic_override local_apic_override;
+ struct MADT_io_sapic io_sapic;
+ struct MADT_local_sapic local_sapic;
+ struct MADT_int_src int_src;
+ } body;
+} __packed;
+
+struct MADTbody {
+ u_int32_t lapic_addr;
+ u_int32_t flags;
+#define ACPI_APIC_FLAG_PCAT_COMPAT 1 /* System has dual-8259 setup. */
+ u_char body[1];
+} __packed;
+
+/*
+ * Addresses to scan on ia32 for the RSD PTR. According to section 5.2.2
+ * of the ACPI spec, we only consider two regions for the base address:
+ * 1. EBDA (1 KB area addressed to by 16 bit pointer at 0x40E)
+ * 2. High memory (0xE0000 - 0xFFFFF)
+ */
+#define RSDP_EBDA_PTR 0x40E
+#define RSDP_EBDA_SIZE 0x400
+#define RSDP_HI_START 0xE0000
+#define RSDP_HI_SIZE 0x20000
+
+#endif /* !_ACPIDUMP_H_ */
diff --git a/tools/tools/ncpus/biosmptable.c b/tools/tools/ncpus/biosmptable.c
new file mode 100644
index 0000000..da48700
--- /dev/null
+++ b/tools/tools/ncpus/biosmptable.c
@@ -0,0 +1,265 @@
+/*-
+ * Copyright (c) 2005 Sandvine Incorporated. All righs reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * Author: Ed Maste <emaste@phaedrus.sandvine.ca>
+ */
+
+/*
+ * This module detects Intel Multiprocessor spec info (mptable) and returns
+ * the number of cpu's identified.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <unistd.h>
+#include <fcntl.h>
+#include <paths.h>
+#include <err.h>
+
+#include <machine/mptable.h>
+
+#define MPFPS_SIG "_MP_"
+#define MPCTH_SIG "PCMP"
+
+#define PTOV(pa) ((off_t)(pa))
+
+static mpfps_t biosmptable_find_mpfps(void);
+static mpfps_t biosmptable_search_mpfps(off_t base, int length);
+static mpcth_t biosmptable_check_mpcth(off_t addr);
+
+static int memopen(void);
+static void memclose(void);
+
+int
+biosmptable_detect(void)
+{
+ mpfps_t mpfps;
+ mpcth_t mpcth;
+ char buf[16];
+ char *entry_type_p;
+ proc_entry_ptr proc;
+ int ncpu, i;
+
+ if (!memopen())
+ return -1; /* XXX 0? */
+ /* locate and validate the mpfps */
+ mpfps = biosmptable_find_mpfps();
+ mpcth = NULL;
+ if (mpfps == NULL) {
+ ncpu = 0;
+ } else if (mpfps->config_type != 0) {
+ /*
+ * If thie config_type is nonzero then this is a default configuration
+ * from Chapter 5 in the MP spec. Report 2 cpus and 1 I/O APIC.
+ */
+ ncpu = 2;
+ } else {
+ ncpu = 0;
+ mpcth = biosmptable_check_mpcth(PTOV(mpfps->pap));
+ if (mpcth != NULL) {
+ entry_type_p = (char *)(mpcth + 1);
+ for (i = 0; i < mpcth->entry_count; i++) {
+ switch (*entry_type_p) {
+ case 0:
+ entry_type_p += sizeof(struct PROCENTRY);
+ proc = (proc_entry_ptr) entry_type_p;
+ warnx("MPTable: Found CPU APIC ID %d %s",
+ proc->apic_id,
+ proc->cpu_flags & PROCENTRY_FLAG_EN ?
+ "enabled" : "disabled");
+ if (proc->cpu_flags & PROCENTRY_FLAG_EN)
+ ncpu++;
+ break;
+ case 1:
+ entry_type_p += sizeof(struct BUSENTRY);
+ break;
+ case 2:
+ entry_type_p += sizeof(struct IOAPICENTRY);
+ break;
+ case 3:
+ case 4:
+ entry_type_p += sizeof(struct INTENTRY);
+ break;
+ default:
+ warnx("unknown mptable entry type (%d)", *entry_type_p);
+ goto done; /* XXX error return? */
+ }
+ }
+ done:
+ ;
+ }
+ }
+ memclose();
+ if (mpcth != NULL)
+ free(mpcth);
+ if (mpfps != NULL)
+ free(mpfps);
+
+ return ncpu;
+}
+
+static int pfd = -1;
+
+static int
+memopen(void)
+{
+ if (pfd < 0) {
+ pfd = open(_PATH_MEM, O_RDONLY);
+ if (pfd < 0)
+ warn("%s: cannot open", _PATH_MEM);
+ }
+ return pfd >= 0;
+}
+
+static void
+memclose(void)
+{
+ if (pfd >= 0) {
+ close(pfd);
+ pfd = -1;
+ }
+}
+
+static int
+memread(off_t addr, void* entry, size_t size)
+{
+ if (pread(pfd, entry, size, addr) != size) {
+ warn("pread (%lu @ 0x%lx)", size, addr);
+ return 0;
+ }
+ return 1;
+}
+
+
+/*
+ * Find the MP Floating Pointer Structure. See the MP spec section 4.1.
+ */
+static mpfps_t
+biosmptable_find_mpfps(void)
+{
+ mpfps_t mpfps;
+ uint16_t addr;
+
+ /* EBDA is the 1 KB addressed by the 16 bit pointer at 0x40E. */
+ if (!memread(PTOV(0x40E), &addr, sizeof(addr)))
+ return (NULL);
+ mpfps = biosmptable_search_mpfps(PTOV(addr << 4), 0x400);
+ if (mpfps != NULL)
+ return (mpfps);
+
+ /* Check the BIOS. */
+ mpfps = biosmptable_search_mpfps(PTOV(0xf0000), 0x10000);
+ if (mpfps != NULL)
+ return (mpfps);
+
+ return (NULL);
+}
+
+static mpfps_t
+biosmptable_search_mpfps(off_t base, int length)
+{
+ mpfps_t mpfps;
+ u_int8_t *cp, sum;
+ int ofs, idx;
+
+ mpfps = malloc(sizeof(*mpfps));
+ if (mpfps == NULL) {
+ warnx("unable to malloc space for MP Floating Pointer Structure");
+ return (NULL);
+ }
+ /* search on 16-byte boundaries */
+ for (ofs = 0; ofs < length; ofs += 16) {
+ if (!memread(base + ofs, mpfps, sizeof(*mpfps)))
+ break;
+
+ /* compare signature, validate checksum */
+ if (!strncmp(mpfps->signature, MPFPS_SIG, strlen(MPFPS_SIG))) {
+ cp = (u_int8_t *)mpfps;
+ sum = 0;
+ /* mpfps is 16 bytes, or one "paragraph" */
+ if (mpfps->length != 1) {
+ warnx("bad mpfps length (%d)", mpfps->length);
+ continue;
+ }
+ for (idx = 0; idx < mpfps->length * 16; idx++)
+ sum += *(cp + idx);
+ if (sum != 0) {
+ warnx("bad mpfps checksum (%d)\n", sum);
+ continue;
+ }
+ return (mpfps);
+ }
+ }
+ free(mpfps);
+ return (NULL);
+}
+
+static mpcth_t
+biosmptable_check_mpcth(off_t addr)
+{
+ mpcth_t mpcth;
+ u_int8_t *cp, sum;
+ int idx, table_length;
+
+ /* mpcth must be in the first 1MB */
+ if ((u_int32_t)addr >= 1024 * 1024) {
+ warnx("bad mpcth address (0x%lx)\n", addr);
+ return (NULL);
+ }
+
+ mpcth = malloc(sizeof(*mpcth));
+ if (mpcth == NULL) {
+ warnx("unable to malloc space for MP Configuration Table Header");
+ return (NULL);
+ }
+ if (!memread(addr, mpcth, sizeof(*mpcth)))
+ goto bad;
+ /* Compare signature and validate checksum. */
+ if (strncmp(mpcth->signature, MPCTH_SIG, strlen(MPCTH_SIG)) != 0) {
+ warnx("bad mpcth signature");
+ goto bad;
+ }
+ table_length = mpcth->base_table_length;
+ mpcth = (mpcth_t) realloc(mpcth, table_length);
+ if (mpcth == NULL) {
+ warnx("unable to realloc space for mpcth (len %u)", table_length);
+ return (NULL);
+ }
+ if (!memread(addr, mpcth, table_length))
+ goto bad;
+ cp = (u_int8_t *)mpcth;
+ sum = 0;
+ for (idx = 0; idx < mpcth->base_table_length; idx++)
+ sum += *(cp + idx);
+ if (sum != 0) {
+ warnx("bad mpcth checksum (%d)", sum);
+ goto bad;
+ }
+
+ return mpcth;
+bad:
+ free(mpcth);
+ return (NULL);
+}
diff --git a/tools/tools/ncpus/ncpus.c b/tools/tools/ncpus/ncpus.c
new file mode 100644
index 0000000..f0d3a6b
--- /dev/null
+++ b/tools/tools/ncpus/ncpus.c
@@ -0,0 +1,14 @@
+/* $FreeBSD$ */
+
+#include <stdio.h>
+
+extern int acpi_detect(void);
+extern int biosmptable_detect(void);
+
+int
+main(int argc, char *argv[])
+{
+ printf("acpi: %d\n", acpi_detect());
+ printf("mptable: %d\n", biosmptable_detect());
+ return 0;
+}
OpenPOWER on IntegriCloud