> On Jul 2, 2019, at 10:39 PM, Paolo Bonzini <pbonzini@xxxxxxxxxx> wrote: > > On 03/07/19 01:39, Nadav Amit wrote: >>> On Jul 2, 2019, at 11:28 AM, Paolo Bonzini <pbonzini@xxxxxxxxxx> wrote: >>> >>> On 02/07/19 19:45, Nadav Amit wrote: >>>>>> I know you are not “serious”, but I’ll use this opportunity for a small >>>>>> clarification. You do need to provide the real number of CPUs as otherwise >>>>>> things will fail. I do not use cpuid, as my machine, for example has two >>>>>> sockets. Decoding the ACPI tables is the right way, but I was too lazy to >>>>>> implement it. >>>>> What about the mptables, too? >>>> If you mean to reuse mptable.c from [1] or [2] - I can give it a shot. I am >>>> not about to write my own parser. >>> >>> Sure. >> >> So mptable logic works on a couple of my machines, but not all. > > Can you send the patch anyway? I can use it as a start for writing a > MADT parser. Sure, it could have used some more work… The original code is surprisingly ugly. Sorry for not doing it myself - but believe me when I tell you that enabling KVM to run on bare-metal is a misery which already took substantial of time. If only I had an ITP things could have been so much easier... Anyhow, here is the code - it does not really use the number of CPUs, but just shows it. -- >8 -- Subject: [PATCH] x86: mptables parsing Signed-off-by: Nadav Amit <nadav.amit@xxxxxxxxx> --- lib/x86/mptable.c | 220 ++++++++++++++++++++++++++++++++++++++++++++ lib/x86/mptable.h | 6 ++ x86/Makefile.common | 1 + x86/cstart64.S | 1 + 4 files changed, 228 insertions(+) create mode 100644 lib/x86/mptable.c create mode 100644 lib/x86/mptable.h diff --git a/lib/x86/mptable.c b/lib/x86/mptable.c new file mode 100644 index 0000000..52ae5cd --- /dev/null +++ b/lib/x86/mptable.c @@ -0,0 +1,220 @@ +/* + * Copyright (c) 1996, by Steve Passe + * All rights reserved. + * + * hacked to make it work in userspace Linux by Ingo Molnar, same copyright + * Re-hacked to make suitable for KVM-unit-tests by Nadav Amit + * + * 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. The name of the developer may NOT be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * 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. + */ + +#include "libcflat.h" +#include "mptable.h" + +/* EBDA is @ 40:0e in real-mode terms */ +#define EBDA_POINTER 0x040e /* location of EBDA pointer */ + +/* CMOS 'top of mem' is @ 40:13 in real-mode terms */ +#define TOPOFMEM_POINTER 0x0413 /* BIOS: base memory size */ + +#define DEFAULT_TOPOFMEM 0xa0000 + +#define BIOS_BASE 0xf0000 +#define BIOS_BASE2 0xe0000 +#define BIOS_SIZE 0x10000 + +#define GROPE_AREA1 0x80000 +#define GROPE_AREA2 0x90000 +#define GROPE_SIZE 0x10000 + +#define PROCENTRY_FLAG_EN 0x01 +#define PROCENTRY_FLAG_BP 0x02 + +/* MP Floating Pointer Structure */ +struct mpfps { + char signature[4]; + uint32_t pap; + uint8_t length; + uint8_t spec_rev; + uint8_t checksum; + uint8_t mpfb1; + uint8_t mpfb2; + uint8_t mpfb3; + uint8_t mpfb4; + uint8_t mpfb5; +} __attribute__((packed)); + +struct proc_entry { + uint8_t type; + uint8_t apicID; + uint8_t apicVersion; + uint8_t cpuFlags; + uint32_t cpuSignature; + uint32_t featureFlags; + uint32_t reserved1; + uint32_t reserved2; +} __attribute__((packed)); + +/* MP Configuration Table Header */ +struct mpcth { + char signature[4]; + uint16_t base_table_length; + uint8_t spec_rev; + uint8_t checksum; + uint8_t oem_id[8]; + uint8_t product_id[12]; + uint32_t oem_table_pointer; + uint16_t oem_table_size; + uint16_t entry_count; + uint32_t apic_address; + uint16_t extended_table_length; + uint8_t extended_table_checksum; + uint8_t reserved; + struct proc_entry entries[0]; +} __attribute__((packed)); + +static void read_proc_entry(struct proc_entry *entry) +{ + int t, family, model; + + printf("#\t%2d", (int) entry->apicID); + printf("\t 0x%2x", (unsigned int) entry->apicVersion); + + printf("\t %s, %s", + (entry->cpuFlags & PROCENTRY_FLAG_BP) ? "BSP" : "AP", + (entry->cpuFlags & PROCENTRY_FLAG_EN) ? "usable" : "unusable"); + + t = (int) entry->cpuSignature; + family = (t >> 8) & 0xf; + model = (t >> 4) & 0xf; + if (family == 0xf) { + family += (t >> 20) & 0xff; + model += (t >> 12) & 0xf0; + } + + printf("\t %d\t %d\t %d", family, model, t & 0xf); + printf("\t 0x%04x\n", entry->featureFlags); +} + +static int mp_config_table_header(uint32_t pap) +{ + struct mpcth *cth = (struct mpcth *)(unsigned long)pap; + int c; + + if (!cth) { + printf("MP Configuration Table Header MISSING!\n"); + return 1; + } + + /* process all the CPUs */ + printf("MP Table:\n#\tAPIC ID\tVersion\tState\t\tFamily\tModel\tStep\tFlags\n"); + for (c = 0; c < cth->entry_count && cth->entries[c].type == 0; c++) + read_proc_entry(&cth->entries[c]); + + printf("\n"); + + return c; +} + +static struct mpfps *find_signature(unsigned long addr, unsigned int size) +{ + struct mpfps *mpfps = (struct mpfps *)addr; + const char MP_SIG[]="_MP_"; + unsigned int i; + + for (i = 0; i < size / sizeof(mpfps); i++) { + if (!strncmp(mpfps[i].signature, MP_SIG, 4)) + return &mpfps[i]; + } + return NULL; +} + +struct mem_location { + unsigned long addr; + unsigned long size; +}; + +const struct mem_location acpi_locations[] = { + { DEFAULT_TOPOFMEM - 1024, 1024 }, + { BIOS_BASE, BIOS_SIZE }, + { BIOS_BASE2, BIOS_SIZE }, + { GROPE_AREA1, GROPE_SIZE }, + { GROPE_AREA2, GROPE_SIZE }, + { 0, 0 } +}; + +static struct mpfps *apic_probe(void) +{ + const struct mem_location *loc = acpi_locations; + uint16_t segment; + unsigned long target; + struct mpfps *mpfps; + + /* search Extended Bios Data Area, if present */ + segment = *(uint16_t *)EBDA_POINTER; + + if (segment == 0) + return NULL; + + printf("\nEBDA points to: %x\n", segment); + + target = (unsigned long)segment << 4; + printf("EBDA segment ptr: %lx\n", target); + + mpfps = find_signature(target, 1024); + if (mpfps) + return mpfps; + + /* read CMOS for real top of mem */ + segment = *(uint16_t *)TOPOFMEM_POINTER; + --segment; /* less ONE_KBYTE */ + target = segment * 1024; + + mpfps = find_signature(target, 1024); + if (mpfps) + return mpfps; + + for (loc = acpi_locations; loc->addr != 0; loc++) { + mpfps = find_signature(loc->addr, loc->size); + if (mpfps) + return mpfps; + } + + return NULL; +} + +int enumerate_cpus(void) +{ + struct mpfps *mpfps; + + /* probe for MP structures */ + mpfps = apic_probe(); + if (mpfps == NULL) { + printf("Could not find MP structures\n"); + return 1; + } + + /* check whether an MP config table exists */ + if (mpfps->mpfb1) + return 1; + + return mp_config_table_header(mpfps->pap); +} diff --git a/lib/x86/mptable.h b/lib/x86/mptable.h new file mode 100644 index 0000000..c4fd098 --- /dev/null +++ b/lib/x86/mptable.h @@ -0,0 +1,6 @@ +#ifndef CFLAT_MPTABLE_H +#define CFLAT_MPTABLE_H + +int enumerate_cpus(void); + +#endif diff --git a/x86/Makefile.common b/x86/Makefile.common index e612dbe..137e6d5 100644 --- a/x86/Makefile.common +++ b/x86/Makefile.common @@ -21,6 +21,7 @@ cflatobjs += lib/x86/acpi.o cflatobjs += lib/x86/stack.o cflatobjs += lib/x86/fault_test.o cflatobjs += lib/x86/delay.o +cflatobjs += lib/x86/mptable.o OBJDIRS += lib/x86 diff --git a/x86/cstart64.S b/x86/cstart64.S index cc7926a..0844b2a 100644 --- a/x86/cstart64.S +++ b/x86/cstart64.S @@ -247,6 +247,7 @@ start64: mov mb_boot_info(%rip), %rbx mov %rbx, %rdi call setup_multiboot + call enumerate_cpus call setup_libcflat mov mb_cmdline(%rbx), %eax mov %rax, __args(%rip) -- 2.17.1