From 85f2668898ba1eb50bf1ea6271b4fe28123f58e5 Mon Sep 17 00:00:00 2001 From: Stefano Ceccherini Date: Mon, 21 Jul 2008 07:13:51 +0000 Subject: [PATCH] Patch by Dustin Howett (GSOC): Move ACPI probing out of the bootloader's smp init and into its own unit. ACPI tables can now generally be found with acpi_find_table(signature). git-svn-id: file:///srv/svn/repos/haiku/haiku/trunk@26538 a95241bf-73f2-0310-859d-f6bbb57e9c96 --- .../arch/x86/{smp_acpi.h => arch_acpi.h} | 33 +++-- .../arch/x86/{smp_apic.h => arch_apic.h} | 7 +- src/system/boot/platform/bios_ia32/Jamfile | 1 + src/system/boot/platform/bios_ia32/acpi.cpp | 111 ++++++++++++++ src/system/boot/platform/bios_ia32/acpi.h | 28 ++++ src/system/boot/platform/bios_ia32/smp.cpp | 137 ++++++------------ src/system/boot/platform/bios_ia32/start.c | 2 + src/system/kernel/arch/x86/arch_int.c | 2 +- src/system/kernel/arch/x86/arch_smp.c | 2 +- src/system/kernel/arch/x86/timers/x86_apic.c | 2 +- 10 files changed, 207 insertions(+), 118 deletions(-) rename headers/private/kernel/arch/x86/{smp_acpi.h => arch_acpi.h} (76%) rename headers/private/kernel/arch/x86/{smp_apic.h => arch_apic.h} (96%) create mode 100644 src/system/boot/platform/bios_ia32/acpi.cpp create mode 100644 src/system/boot/platform/bios_ia32/acpi.h diff --git a/headers/private/kernel/arch/x86/smp_acpi.h b/headers/private/kernel/arch/x86/arch_acpi.h similarity index 76% rename from headers/private/kernel/arch/x86/smp_acpi.h rename to headers/private/kernel/arch/x86/arch_acpi.h index 4c5338feb8..38ab0a2d0e 100644 --- a/headers/private/kernel/arch/x86/smp_acpi.h +++ b/headers/private/kernel/arch/x86/arch_acpi.h @@ -1,9 +1,10 @@ /* + * Copyright 2008, Dustin Howett, dustin.howett@gmail.com. All rights reserved. * Copyright 2007, Michael Lotz, mmlr@mlotz.ch. All rights reserved. * Distributed under the terms of the MIT License. */ -#ifndef _KERNEL_ARCH_x86_SMP_ACPI_H -#define _KERNEL_ARCH_x86_SMP_ACPI_H +#ifndef _KERNEL_ARCH_x86_ARCH_ACPI_H +#define _KERNEL_ARCH_x86_ARCH_ACPI_H #define ACPI_RSDP_SIGNATURE "RSD PTR " #define ACPI_RSDT_SIGNATURE "RSDT" @@ -11,7 +12,7 @@ #define ACPI_LOCAL_APIC_ENABLED 0x01 -struct acpi_rsdp { +typedef struct acpi_rsdp { char signature[8]; /* "RSD PTR " including blank */ uint8 checksum; /* checksum of bytes 0-19 (per ACPI 1.0) */ char oem_id[6]; /* not null terminated */ @@ -21,9 +22,9 @@ struct acpi_rsdp { uint64 xsdt_address; /* 64bit physical memory address of XSDT */ uint8 extended_checksum; /* including entire table */ uint8 reserved[3]; -} _PACKED; +} _PACKED acpi_rsdp; -struct acpi_descriptor_header { +typedef struct acpi_descriptor_header { char signature[4]; /* table identifier as ASCII string */ uint32 length; /* length in bytes of the entire table */ uint8 revision; @@ -33,39 +34,39 @@ struct acpi_descriptor_header { uint32 oem_revision; /* oem supplied revision number */ char creator_id[4]; /* creator / asl compiler id */ uint32 creator_revision; /* compiler revision */ -} _PACKED; +} _PACKED acpi_descriptor_header; -struct acpi_madt { - acpi_descriptor_header header; /* "APIC" signature */ +typedef struct acpi_madt { + acpi_descriptor_header header; /* "APIC" signature */ uint32 local_apic_address; /* physical address for local CPUs APICs */ uint32 flags; -} _PACKED; +} _PACKED acpi_madt; enum { ACPI_MADT_LOCAL_APIC = 0, ACPI_MADT_IO_APIC = 1 }; -struct acpi_apic { +typedef struct acpi_apic { uint8 type; uint8 length; -} _PACKED; +} _PACKED acpi_apic; -struct acpi_local_apic { +typedef struct acpi_local_apic { uint8 type; /* 0 = processor local APIC */ uint8 length; /* 8 bytes */ uint8 acpi_processor_id; uint8 apic_id; /* the id of this APIC */ uint32 flags; /* 1 = enabled */ -} _PACKED; +} _PACKED acpi_local_apic; -struct acpi_io_apic { +typedef struct acpi_io_apic { uint8 type; /* 1 = I/O APIC */ uint8 length; /* 12 bytes */ uint8 io_apic_id; /* the id of this APIC */ uint8 reserved; uint32 io_apic_address; /* phyisical address of I/O APIC */ uint32 interrupt_base; /* global system interrupt base */ -} _PACKED; +} _PACKED acpi_io_apic; -#endif /* _KERNEL_ARCH_x86_SMP_ACPI_H */ +#endif /* _KERNEL_ARCH_x86_ARCH_ACPI_H */ diff --git a/headers/private/kernel/arch/x86/smp_apic.h b/headers/private/kernel/arch/x86/arch_apic.h similarity index 96% rename from headers/private/kernel/arch/x86/smp_apic.h rename to headers/private/kernel/arch/x86/arch_apic.h index 76ef69e8a9..5613e3ceb9 100644 --- a/headers/private/kernel/arch/x86/smp_apic.h +++ b/headers/private/kernel/arch/x86/arch_apic.h @@ -1,12 +1,13 @@ /* + * Copyright 2008, Dustin Howett, dustin.howett@gmail.com. All rights reserved. * Copyright 2005, Axel Dörfler, axeld@pinc-software.de. All rights reserved. * Distributed under the terms of the MIT License. * * Copyright 2001-2002, Travis Geiselbrecht. All rights reserved. * Distributed under the terms of the NewOS License. */ -#ifndef _KERNEL_ARCH_x86_SMP_APIC_H -#define _KERNEL_ARCH_x86_SMP_APIC_H +#ifndef _KERNEL_ARCH_x86_ARCH_APIC_H +#define _KERNEL_ARCH_x86_ARCH_APIC_H #define MP_FLOATING_SIGNATURE '_PM_' #define MP_CONFIG_TABLE_SIGNATURE 'PCMP' @@ -191,4 +192,4 @@ enum { MP_INTR_TYPE_ExtINT, }; -#endif /* _KERNEL_ARCH_x86_SMP_APIC_H */ +#endif /* _KERNEL_ARCH_x86_ARCH_APIC_H */ diff --git a/src/system/boot/platform/bios_ia32/Jamfile b/src/system/boot/platform/bios_ia32/Jamfile index c4f31319c2..a60f82c1f1 100644 --- a/src/system/boot/platform/bios_ia32/Jamfile +++ b/src/system/boot/platform/bios_ia32/Jamfile @@ -29,6 +29,7 @@ KernelMergeObject boot_platform_bios_ia32.o : menu.cpp mmu.cpp cpu.cpp + acpi.cpp smp.cpp smp_trampoline.S support.S diff --git a/src/system/boot/platform/bios_ia32/acpi.cpp b/src/system/boot/platform/bios_ia32/acpi.cpp new file mode 100644 index 0000000000..eb240f787b --- /dev/null +++ b/src/system/boot/platform/bios_ia32/acpi.cpp @@ -0,0 +1,111 @@ +/* + * Copyright 2008, Dustin Howett, dustin.howett@gmail.com. All rights reserved. + * Copyright 2007, Michael Lotz, mmlr@mlotz.ch + * Copyright 2004-2005, Axel Dörfler, axeld@pinc-software.de. + * Distributed under the terms of the MIT License. + * + * Copyright 2001, Travis Geiselbrecht. All rights reserved. + * Distributed under the terms of the NewOS License. +*/ + + +#include "acpi.h" +#include "mmu.h" + +#include + +#include + +#include + +//#define TRACE_ACPI +#ifdef TRACE_ACPI +# define TRACE(x) dprintf x +#else +# define TRACE(x) ; +#endif + +static struct scan_spots_struct acpi_scan_spots[] = { + { 0x0, 0x400, 0x400 - 0x0 }, + { 0xe0000, 0x100000, 0x100000 - 0xe0000 }, + { 0, 0, 0 } +}; + +static acpi_descriptor_header *sAcpiRsdt; // System Description Table + + +static status_t +acpi_check_rsdt(acpi_rsdp *rsdp) +{ + TRACE(("acpi: found rsdp at %p oem id: %.6s\n", rsdp, rsdp->oem_id)); + TRACE(("acpi: rsdp points to rsdt at 0x%lx\n", rsdp->rsdt_address)); + + // map and validate the root system description table + acpi_descriptor_header *rsdt + = (acpi_descriptor_header *)mmu_map_physical_memory( + rsdp->rsdt_address, B_PAGE_SIZE, kDefaultPageFlags); + if (!rsdt || strncmp(rsdt->signature, ACPI_RSDT_SIGNATURE, 4) != 0) { + TRACE(("acpi: invalid root system description table\n")); + return B_ERROR; + } + + sAcpiRsdt = rsdt; + return B_OK; +} + + +acpi_descriptor_header * +acpi_find_table(char *signature) +{ + if (sAcpiRsdt == NULL) { + return NULL; + } + + // Tried to keep numEntries a static variable; kept turning up 0 on table scan + // TODO: This calculates numEntries for every acpi probe. + int32 numEntries = (sAcpiRsdt->length - sizeof(acpi_descriptor_header)) / 4; + if (numEntries <= 0) { + TRACE(("acpi: root system description table is empty\n")); + return NULL; + } + + TRACE(("acpi: searching %ld entries for table '%.4s'\n", numEntries, signature)); + uint32 *pointer = (uint32 *)((uint8 *)sAcpiRsdt + sizeof(acpi_descriptor_header)); + for (int32 j = 0; j < numEntries; j++, pointer++) { + acpi_descriptor_header *header = (acpi_descriptor_header *) + mmu_map_physical_memory(*pointer, B_PAGE_SIZE, kDefaultPageFlags); + if (!header || strncmp(header->signature, signature, 4) != 0) { + // not interesting for us + TRACE(("acpi: Looking for '%.4s'. Skipping '%.4s'\n", signature, header->signature)); + continue; + } + TRACE(("acpi: Found '%.4s' @ %p\n", signature)); + return header; + } + + // If we didn't find the table, return NULL. + return NULL; +} + + +void +acpi_init(void) +{ + acpi_rsdp *rsdp = NULL; + // Try to find the ACPI RSDP. + for (int32 i = 0; acpi_scan_spots[i].length > 0; i++) { + char *pointer; + TRACE(("acpi_init: entry base 0x%lx, limit 0x%lx\n", acpi_scan_spots[i].start, + acpi_scan_spots[i].stop)); + for (pointer = (char *)acpi_scan_spots[i].start; + (uint32)pointer < acpi_scan_spots[i].stop; pointer += 16) { + if (strncmp(pointer, ACPI_RSDP_SIGNATURE, 8) == 0) { + TRACE(("acpi_init: found ACPI RSDP signature at %p\n", pointer)); + rsdp = (acpi_rsdp *)pointer; + } + } + if (acpi_check_rsdt(rsdp) == B_OK) + break; + } + +} diff --git a/src/system/boot/platform/bios_ia32/acpi.h b/src/system/boot/platform/bios_ia32/acpi.h new file mode 100644 index 0000000000..26847d823b --- /dev/null +++ b/src/system/boot/platform/bios_ia32/acpi.h @@ -0,0 +1,28 @@ +/* + * Copyright 2005, Axel Dörfler, axeld@pinc-software.de. All rights reserved. + * Distributed under the terms of the MIT License. + */ +#ifndef ACPI_H +#define ACPI_H + +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +struct scan_spots_struct { + uint32 start; + uint32 stop; + uint32 length; +}; + +acpi_descriptor_header *acpi_find_table(char *signature); +void acpi_init(void); + +#ifdef __cplusplus +} +#endif + +#endif /* ACPI_H */ diff --git a/src/system/boot/platform/bios_ia32/smp.cpp b/src/system/boot/platform/bios_ia32/smp.cpp index 2437a67de7..be7799d717 100644 --- a/src/system/boot/platform/bios_ia32/smp.cpp +++ b/src/system/boot/platform/bios_ia32/smp.cpp @@ -1,4 +1,5 @@ /* + * Copyright 2008, Dustin Howett, dustin.howett@gmail.com. All rights reserved. * Copyright 2004-2005, Axel Dörfler, axeld@pinc-software.de. * Distributed under the terms of the MIT License. * @@ -9,6 +10,7 @@ #include "smp.h" #include "mmu.h" +#include "acpi.h" #include @@ -16,8 +18,8 @@ #include #include #include -#include -#include +#include +#include #include #include @@ -36,24 +38,12 @@ struct gdt_idt_descr { uint32 *b; } _PACKED; -struct smp_scan_spots_struct { - uint32 start; - uint32 stop; - uint32 length; -}; - -static struct smp_scan_spots_struct smp_scan_spots[] = { +static struct scan_spots_struct smp_scan_spots[] = { { 0x9fc00, 0xa0000, 0xa0000 - 0x9fc00 }, { 0xf0000, 0x100000, 0x100000 - 0xf0000 }, { 0, 0, 0 } }; -static struct smp_scan_spots_struct acpi_scan_spots[] = { - { 0x0, 0x400, 0x400 - 0x0 }, - { 0xe0000, 0x100000, 0x100000 - 0xe0000 }, - { 0, 0, 0 } -}; - extern "C" void execute_n_instructions(int count); extern "C" void smp_trampoline(void); @@ -103,21 +93,6 @@ smp_mp_probe(uint32 base, uint32 limit) } -static acpi_rsdp * -smp_acpi_probe(uint32 base, uint32 limit) -{ - TRACE(("smp_acpi_probe: entry base 0x%lx, limit 0x%lx\n", base, limit)); - for (char *pointer = (char *)base; (uint32)pointer < limit; pointer += 16) { - if (strncmp(pointer, ACPI_RSDP_SIGNATURE, 8) == 0) { - TRACE(("smp_acpi_probe: found ACPI RSDP signature at %p\n", pointer)); - return (acpi_rsdp *)pointer; - } - } - - return NULL; -} - - static status_t smp_do_mp_config(mp_floating_struct *floatingStruct) { @@ -241,85 +216,59 @@ smp_do_mp_config(mp_floating_struct *floatingStruct) static status_t -smp_do_acpi_config(acpi_rsdp *rsdp) +smp_do_acpi_config(void) { TRACE(("smp: using ACPI to detect MP configuration\n")); - TRACE(("smp: found rsdp at %p oem id: %.6s\n", rsdp, rsdp->oem_id)); - TRACE(("smp: rsdp points to rsdt at 0x%lx\n", rsdp->rsdt_address)); // reset CPU count gKernelArgs.num_cpus = 0; - // map and validate the root system description table - acpi_descriptor_header *rsdt - = (acpi_descriptor_header *)mmu_map_physical_memory( - rsdp->rsdt_address, B_PAGE_SIZE, kDefaultPageFlags); - if (!rsdt || strncmp(rsdt->signature, ACPI_RSDT_SIGNATURE, 4) != 0) { - TRACE(("smp: invalid root system description table\n")); + acpi_madt *madt = (acpi_madt *)acpi_find_table(ACPI_MADT_SIGNATURE); + + if (madt == NULL) { + TRACE(("smp: Failed to find MADT!\n")); return B_ERROR; } - int32 numEntries = (rsdt->length - sizeof(acpi_descriptor_header)) / 4; - if (numEntries <= 0) { - TRACE(("smp: root system description table is empty\n")); - return B_ERROR; - } + gKernelArgs.arch_args.apic_phys = madt->local_apic_address; + TRACE(("smp: local apic address is 0x%lx\n", madt->local_apic_address)); - TRACE(("smp: searching %ld entries for APIC information\n", numEntries)); - uint32 *pointer = (uint32 *)((uint8 *)rsdt + sizeof(acpi_descriptor_header)); - for (int32 j = 0; j < numEntries; j++, pointer++) { - acpi_descriptor_header *header = (acpi_descriptor_header *) - mmu_map_physical_memory(*pointer, B_PAGE_SIZE, kDefaultPageFlags); - if (!header || strncmp(header->signature, ACPI_MADT_SIGNATURE, 4) != 0) { - // not interesting for us - TRACE(("smp: skipping uninteresting header '%.4s'\n", header->signature)); - continue; - } - - acpi_madt *madt = (acpi_madt *)header; - gKernelArgs.arch_args.apic_phys = madt->local_apic_address; - TRACE(("smp: local apic address is 0x%lx\n", madt->local_apic_address)); - - acpi_apic *apic = (acpi_apic *)((uint8 *)madt + sizeof(acpi_madt)); - acpi_apic *end = (acpi_apic *)((uint8 *)madt + header->length); - while (apic < end) { - switch (apic->type) { - case ACPI_MADT_LOCAL_APIC: - { - if (gKernelArgs.num_cpus == MAX_BOOT_CPUS) { - TRACE(("smp: already reached maximum boot CPUs (%d)\n", MAX_BOOT_CPUS)); - break; - } - - acpi_local_apic *localApic = (acpi_local_apic *)apic; - TRACE(("smp: found local APIC with id %u\n", localApic->apic_id)); - if ((localApic->flags & ACPI_LOCAL_APIC_ENABLED) == 0) { - TRACE(("smp: APIC is disabled and will not be used\n")); - break; - } - - gKernelArgs.arch_args.cpu_apic_id[gKernelArgs.num_cpus] = localApic->apic_id; - gKernelArgs.arch_args.cpu_os_id[localApic->apic_id] = gKernelArgs.num_cpus; - // ToDo: how to find out? putting 0x10 in to indicate a local apic - gKernelArgs.arch_args.cpu_apic_version[gKernelArgs.num_cpus] = 0x10; - gKernelArgs.num_cpus++; + acpi_apic *apic = (acpi_apic *)((uint8 *)madt + sizeof(acpi_madt)); + acpi_apic *end = (acpi_apic *)((uint8 *)madt + madt->header.length); + while (apic < end) { + switch (apic->type) { + case ACPI_MADT_LOCAL_APIC: + { + if (gKernelArgs.num_cpus == MAX_BOOT_CPUS) { + TRACE(("smp: already reached maximum boot CPUs (%d)\n", MAX_BOOT_CPUS)); break; } - case ACPI_MADT_IO_APIC: { - acpi_io_apic *ioApic = (acpi_io_apic *)apic; - TRACE(("smp: found io APIC with id %u and address 0x%lx\n", - ioApic->io_apic_id, ioApic->io_apic_address)); - gKernelArgs.arch_args.ioapic_phys = ioApic->io_apic_address; + acpi_local_apic *localApic = (acpi_local_apic *)apic; + TRACE(("smp: found local APIC with id %u\n", localApic->apic_id)); + if ((localApic->flags & ACPI_LOCAL_APIC_ENABLED) == 0) { + TRACE(("smp: APIC is disabled and will not be used\n")); break; } + + gKernelArgs.arch_args.cpu_apic_id[gKernelArgs.num_cpus] = localApic->apic_id; + gKernelArgs.arch_args.cpu_os_id[localApic->apic_id] = gKernelArgs.num_cpus; + // ToDo: how to find out? putting 0x10 in to indicate a local apic + gKernelArgs.arch_args.cpu_apic_version[gKernelArgs.num_cpus] = 0x10; + gKernelArgs.num_cpus++; + break; } - apic = (acpi_apic *)((uint8 *)apic + apic->length); + case ACPI_MADT_IO_APIC: { + acpi_io_apic *ioApic = (acpi_io_apic *)apic; + TRACE(("smp: found io APIC with id %u and address 0x%lx\n", + ioApic->io_apic_id, ioApic->io_apic_address)); + gKernelArgs.arch_args.ioapic_phys = ioApic->io_apic_address; + break; + } } - if (gKernelArgs.num_cpus > 0) - break; + apic = (acpi_apic *)((uint8 *)apic + apic->length); } return gKernelArgs.num_cpus > 0 ? B_OK : B_ERROR; @@ -609,12 +558,8 @@ smp_init(void) // first try to find ACPI tables to get MP configuration as it handles // physical as well as logical MP configurations as in multiple cpus, // multiple cores or hyper threading. - for (int32 i = 0; acpi_scan_spots[i].length > 0; i++) { - acpi_rsdp *rsdp = smp_acpi_probe(smp_scan_spots[i].start, - smp_scan_spots[i].stop); - if (rsdp != NULL && smp_do_acpi_config(rsdp) == B_OK) - return; - } + if (smp_do_acpi_config() == B_OK) + return; // then try to find MPS tables and do configuration based on them for (int32 i = 0; smp_scan_spots[i].length > 0; i++) { diff --git a/src/system/boot/platform/bios_ia32/start.c b/src/system/boot/platform/bios_ia32/start.c index 1fac2525f5..2440336e6e 100644 --- a/src/system/boot/platform/bios_ia32/start.c +++ b/src/system/boot/platform/bios_ia32/start.c @@ -10,6 +10,7 @@ #include "cpu.h" #include "mmu.h" #include "smp.h" +#include "acpi.h" #include "keyboard.h" #include "bios.h" @@ -132,6 +133,7 @@ _start(void) serial_enable(); apm_init(); + acpi_init(); smp_init(); main(&args); } diff --git a/src/system/kernel/arch/x86/arch_int.c b/src/system/kernel/arch/x86/arch_int.c index 4743351208..47defdadad 100644 --- a/src/system/kernel/arch/x86/arch_int.c +++ b/src/system/kernel/arch/x86/arch_int.c @@ -22,7 +22,7 @@ #include #include -#include +#include #include #include diff --git a/src/system/kernel/arch/x86/arch_smp.c b/src/system/kernel/arch/x86/arch_smp.c index 08b347f2df..766456fac9 100644 --- a/src/system/kernel/arch/x86/arch_smp.c +++ b/src/system/kernel/arch/x86/arch_smp.c @@ -20,7 +20,7 @@ #include #include -#include +#include #include #include diff --git a/src/system/kernel/arch/x86/timers/x86_apic.c b/src/system/kernel/arch/x86/timers/x86_apic.c index fe9d0d8a7b..513319cbc8 100644 --- a/src/system/kernel/arch/x86/timers/x86_apic.c +++ b/src/system/kernel/arch/x86/timers/x86_apic.c @@ -11,7 +11,7 @@ #include #include -#include +#include #include #include