From 6cb3a59fd5e754c3627b79db21c5bcc284bfd721 Mon Sep 17 00:00:00 2001 From: Stefan Reinauer Date: Mon, 13 Jul 2015 09:39:15 +0200 Subject: x86: flatten hierarchy It never made sense to have bootblock_* in init, but pirq_routing.c in boot, and some ld scripts on the main level while others live in subdirectories. This patch flattens the directory hierarchy and makes x86 more similar to the other architectures. Change-Id: I4056038fe7813e4d3d3042c441e7ab6076a36384 Signed-off-by: Stefan Reinauer Reviewed-on: http://review.coreboot.org/10901 Tested-by: build bot (Jenkins) Tested-by: Raptor Engineering Automated Test Stand Reviewed-by: Ronald G. Minnich --- src/arch/x86/Makefile.inc | 86 +- src/arch/x86/acpi.c | 1137 ++++++++++++++++++++ src/arch/x86/acpigen.c | 728 +++++++++++++ src/arch/x86/boot.c | 210 ++++ src/arch/x86/boot/Makefile.inc | 22 - src/arch/x86/boot/acpi.c | 1137 -------------------- src/arch/x86/boot/acpigen.c | 728 ------------- src/arch/x86/boot/boot.c | 210 ---- src/arch/x86/boot/cbmem.c | 76 -- src/arch/x86/boot/gdt.c | 62 -- src/arch/x86/boot/mpspec.c | 597 ---------- src/arch/x86/boot/pirq_routing.c | 208 ---- src/arch/x86/boot/smbios.c | 581 ---------- src/arch/x86/boot/tables.c | 221 ---- src/arch/x86/boot/wakeup.S | 99 -- src/arch/x86/bootblock_normal.c | 52 + src/arch/x86/bootblock_simple.c | 23 + src/arch/x86/c_start.S | 421 ++++++++ src/arch/x86/cbfs_and_run.c | 26 + src/arch/x86/cbmem.c | 76 ++ src/arch/x86/cpu.c | 273 +++++ src/arch/x86/cpu_common.c | 65 ++ src/arch/x86/crt0_romcc_epilogue.inc | 21 + src/arch/x86/ebda.c | 52 + src/arch/x86/exception.c | 511 +++++++++ src/arch/x86/failover.ld | 70 ++ src/arch/x86/gdt.c | 62 ++ src/arch/x86/id.inc | 18 + src/arch/x86/id.ld | 6 + src/arch/x86/init/Makefile.inc | 1 - src/arch/x86/init/bootblock_normal.c | 52 - src/arch/x86/init/bootblock_simple.c | 23 - src/arch/x86/init/crt0_romcc_epilogue.inc | 21 - src/arch/x86/init/failover.ld | 70 -- src/arch/x86/init/prologue.inc | 23 - src/arch/x86/init/romstage.ld | 87 -- src/arch/x86/ioapic.c | 153 +++ src/arch/x86/lib/Makefile.inc | 48 - src/arch/x86/lib/c_start.S | 421 -------- src/arch/x86/lib/cbfs_and_run.c | 26 - src/arch/x86/lib/cpu.c | 273 ----- src/arch/x86/lib/cpu_common.c | 65 -- src/arch/x86/lib/ebda.c | 52 - src/arch/x86/lib/exception.c | 511 --------- src/arch/x86/lib/id.inc | 18 - src/arch/x86/lib/id.ld | 6 - src/arch/x86/lib/ioapic.c | 153 --- src/arch/x86/lib/memcpy.c | 22 - src/arch/x86/lib/memmove.c | 187 ---- src/arch/x86/lib/memset.c | 84 -- src/arch/x86/lib/mmap_boot.c | 75 -- src/arch/x86/lib/pci_ops_conf1.c | 71 -- src/arch/x86/lib/pci_ops_mmconf.c | 61 -- src/arch/x86/lib/romcc_console.c | 87 -- src/arch/x86/lib/stages.c | 25 - src/arch/x86/lib/thread.c | 65 -- src/arch/x86/lib/thread_switch.S | 58 - src/arch/x86/lib/timestamp.c | 26 - src/arch/x86/lib/walkcbfs.S | 117 -- src/arch/x86/memcpy.c | 22 + src/arch/x86/memmove.c | 187 ++++ src/arch/x86/memset.c | 84 ++ src/arch/x86/mmap_boot.c | 75 ++ src/arch/x86/mpspec.c | 597 ++++++++++ src/arch/x86/pci_ops_conf1.c | 71 ++ src/arch/x86/pci_ops_mmconf.c | 61 ++ src/arch/x86/pirq_routing.c | 208 ++++ src/arch/x86/prologue.inc | 23 + src/arch/x86/romcc_console.c | 87 ++ src/arch/x86/romstage.ld | 87 ++ src/arch/x86/smbios.c | 581 ++++++++++ src/arch/x86/stages.c | 25 + src/arch/x86/tables.c | 221 ++++ src/arch/x86/thread.c | 65 ++ src/arch/x86/thread_switch.S | 58 + src/arch/x86/timestamp.c | 26 + src/arch/x86/wakeup.S | 99 ++ src/arch/x86/walkcbfs.S | 117 ++ src/mainboard/bifferos/bifferboard/romstage.c | 2 +- src/mainboard/dmp/vortex86ex/romstage.c | 2 +- src/northbridge/intel/fsp_rangeley/Makefile.inc | 2 +- src/northbridge/intel/fsp_sandybridge/Makefile.inc | 2 +- src/northbridge/intel/haswell/Makefile.inc | 2 +- src/northbridge/intel/nehalem/Makefile.inc | 2 +- src/northbridge/intel/sandybridge/Makefile.inc | 2 +- 85 files changed, 6675 insertions(+), 6692 deletions(-) create mode 100644 src/arch/x86/acpi.c create mode 100644 src/arch/x86/acpigen.c create mode 100644 src/arch/x86/boot.c delete mode 100644 src/arch/x86/boot/Makefile.inc delete mode 100644 src/arch/x86/boot/acpi.c delete mode 100644 src/arch/x86/boot/acpigen.c delete mode 100644 src/arch/x86/boot/boot.c delete mode 100644 src/arch/x86/boot/cbmem.c delete mode 100644 src/arch/x86/boot/gdt.c delete mode 100644 src/arch/x86/boot/mpspec.c delete mode 100644 src/arch/x86/boot/pirq_routing.c delete mode 100644 src/arch/x86/boot/smbios.c delete mode 100644 src/arch/x86/boot/tables.c delete mode 100644 src/arch/x86/boot/wakeup.S create mode 100644 src/arch/x86/bootblock_normal.c create mode 100644 src/arch/x86/bootblock_simple.c create mode 100644 src/arch/x86/c_start.S create mode 100644 src/arch/x86/cbfs_and_run.c create mode 100644 src/arch/x86/cbmem.c create mode 100644 src/arch/x86/cpu.c create mode 100644 src/arch/x86/cpu_common.c create mode 100644 src/arch/x86/crt0_romcc_epilogue.inc create mode 100644 src/arch/x86/ebda.c create mode 100644 src/arch/x86/exception.c create mode 100644 src/arch/x86/failover.ld create mode 100644 src/arch/x86/gdt.c create mode 100644 src/arch/x86/id.inc create mode 100644 src/arch/x86/id.ld delete mode 100644 src/arch/x86/init/Makefile.inc delete mode 100644 src/arch/x86/init/bootblock_normal.c delete mode 100644 src/arch/x86/init/bootblock_simple.c delete mode 100644 src/arch/x86/init/crt0_romcc_epilogue.inc delete mode 100644 src/arch/x86/init/failover.ld delete mode 100644 src/arch/x86/init/prologue.inc delete mode 100644 src/arch/x86/init/romstage.ld create mode 100644 src/arch/x86/ioapic.c delete mode 100644 src/arch/x86/lib/Makefile.inc delete mode 100644 src/arch/x86/lib/c_start.S delete mode 100644 src/arch/x86/lib/cbfs_and_run.c delete mode 100644 src/arch/x86/lib/cpu.c delete mode 100644 src/arch/x86/lib/cpu_common.c delete mode 100644 src/arch/x86/lib/ebda.c delete mode 100644 src/arch/x86/lib/exception.c delete mode 100644 src/arch/x86/lib/id.inc delete mode 100644 src/arch/x86/lib/id.ld delete mode 100644 src/arch/x86/lib/ioapic.c delete mode 100644 src/arch/x86/lib/memcpy.c delete mode 100644 src/arch/x86/lib/memmove.c delete mode 100644 src/arch/x86/lib/memset.c delete mode 100644 src/arch/x86/lib/mmap_boot.c delete mode 100644 src/arch/x86/lib/pci_ops_conf1.c delete mode 100644 src/arch/x86/lib/pci_ops_mmconf.c delete mode 100644 src/arch/x86/lib/romcc_console.c delete mode 100644 src/arch/x86/lib/stages.c delete mode 100644 src/arch/x86/lib/thread.c delete mode 100644 src/arch/x86/lib/thread_switch.S delete mode 100644 src/arch/x86/lib/timestamp.c delete mode 100644 src/arch/x86/lib/walkcbfs.S create mode 100644 src/arch/x86/memcpy.c create mode 100644 src/arch/x86/memmove.c create mode 100644 src/arch/x86/memset.c create mode 100644 src/arch/x86/mmap_boot.c create mode 100644 src/arch/x86/mpspec.c create mode 100644 src/arch/x86/pci_ops_conf1.c create mode 100644 src/arch/x86/pci_ops_mmconf.c create mode 100644 src/arch/x86/pirq_routing.c create mode 100644 src/arch/x86/prologue.inc create mode 100644 src/arch/x86/romcc_console.c create mode 100644 src/arch/x86/romstage.ld create mode 100644 src/arch/x86/smbios.c create mode 100644 src/arch/x86/stages.c create mode 100644 src/arch/x86/tables.c create mode 100644 src/arch/x86/thread.c create mode 100644 src/arch/x86/thread_switch.S create mode 100644 src/arch/x86/timestamp.c create mode 100644 src/arch/x86/wakeup.S create mode 100644 src/arch/x86/walkcbfs.S diff --git a/src/arch/x86/Makefile.inc b/src/arch/x86/Makefile.inc index 2448590ba9..4b61767aed 100644 --- a/src/arch/x86/Makefile.inc +++ b/src/arch/x86/Makefile.inc @@ -19,13 +19,6 @@ ## along with this program; if not, write to the Free Software ## Foundation, Inc. ## -############################################################################### -# Take care of subdirectories -############################################################################### -subdirs-y += boot -# subdirs-y += init -subdirs-y += lib -subdirs-y += smp ################################################################################ # i386 specific tools @@ -74,20 +67,20 @@ CBFS_BASE_ADDRESS=$(call int-add, $(call int-subtract, 0xffffffff $(CONFIG_CBFS_ ifeq ($(CONFIG_ARCH_BOOTBLOCK_X86_32)$(CONFIG_ARCH_BOOTBLOCK_X86_64),y) -bootblock-srcs += $(src)/arch/x86/init/failover.ld +bootblock-srcs += $(src)/arch/x86/failover.ld bootblock-srcs += $(src)/cpu/x86/16bit/entry16.ld bootblock-srcs += $(src)/cpu/x86/16bit/reset16.ld -bootblock-srcs += $(src)/arch/x86/lib/id.ld +bootblock-srcs += $(src)/arch/x86/id.ld ifeq ($(CONFIG_CPU_INTEL_FIRMWARE_INTERFACE_TABLE),y) bootblock-srcs += $(src)/cpu/intel/fit/fit.ld endif # TODO: Why can't this use the real bootblock-y += xxx.S mechanism instead? -bootblock_inc = $(src)/arch/x86/init/prologue.inc +bootblock_inc = $(src)/arch/x86/prologue.inc bootblock_inc += $(src)/cpu/x86/16bit/entry16.inc bootblock_inc += $(src)/cpu/x86/16bit/reset16.inc bootblock_inc += $(src)/cpu/x86/32bit/entry32.inc -bootblock_inc += $(src)/arch/x86/lib/id.inc +bootblock_inc += $(src)/arch/x86/id.inc ifeq ($(CONFIG_CPU_INTEL_FIRMWARE_INTERFACE_TABLE),y) bootblock_inc += $(src)/cpu/intel/fit/fit.inc endif @@ -97,7 +90,7 @@ ifeq ($(CONFIG_SSE),y) bootblock_inc += $(src)/cpu/x86/sse_enable.inc endif bootblock_inc += $(objgenerated)/bootblock.inc -bootblock_inc += $(src)/arch/x86/lib/walkcbfs.S +bootblock_inc += $(src)/arch/x86/walkcbfs.S bootblock_romccflags := -mcpu=i386 -O2 -D__PRE_RAM__ -D__BOOTBLOCK__ ifeq ($(CONFIG_SSE),y) @@ -121,7 +114,7 @@ $(objgenerated)/bootblock.s: $(objgenerated)/bootblock_inc.S $(obj)/config.h $(o @printf " CC $(subst $(obj)/,,$(@))\n" $(CC_bootblock) -MMD -x assembler-with-cpp -E -I$(src)/include -I$(src)/arch/x86/include -I$(obj) -include $(obj)/build.h -include $(obj)/config.h -I. -I$(src) $< -o $@ -$(objgenerated)/bootblock.inc: $(src)/arch/x86/init/$(subst ",,$(CONFIG_BOOTBLOCK_SOURCE)) $(objutil)/romcc/romcc $(OPTION_TABLE_H) +$(objgenerated)/bootblock.inc: $(src)/arch/x86/$(subst ",,$(CONFIG_BOOTBLOCK_SOURCE)) $(objutil)/romcc/romcc $(OPTION_TABLE_H) @printf " ROMCC $(subst $(obj)/,,$(@))\n" $(CC_bootblock) $(CPPFLAGS_bootblock) -MM -MT$(objgenerated)/bootblock.inc \ $< > $(objgenerated)/bootblock.inc.d @@ -144,8 +137,8 @@ endif # CONFIG_ARCH_BOOTBLOCK_X86_32 / CONFIG_ARCH_BOOTBLOCK_X86_64 ifeq ($(CONFIG_ARCH_ROMSTAGE_X86_32)$(CONFIG_ARCH_ROMSTAGE_X86_64),y) -crt0s = $(src)/arch/x86/init/prologue.inc -romstage-srcs += $(src)/arch/x86/init/romstage.ld +crt0s = $(src)/arch/x86/prologue.inc +romstage-srcs += $(src)/arch/x86/romstage.ld crt0s += $(src)/cpu/x86/32bit/entry32.inc romstage-srcs += $(src)/cpu/x86/32bit/entry32.ld @@ -160,7 +153,7 @@ crt0s += $(cpu_incs-y) crt0s += $(obj)/mainboard/$(MAINBOARDDIR)/romstage.inc ifeq ($(CONFIG_ROMCC),y) -crt0s += $(src)/arch/x86/init/crt0_romcc_epilogue.inc +crt0s += $(src)/arch/x86/crt0_romcc_epilogue.inc endif ifeq ($(CONFIG_ROMCC),y) @@ -339,3 +332,64 @@ endif endif # CONFIG_ARCH_RAMSTAGE_X86_32 / CONFIG_ARCH_RAMSTAGE_X86_64 +ifeq ($(CONFIG_ARCH_ROMSTAGE_X86_32)$(CONFIG_ARCH_ROMSTAGE_X86_64),y) + +romstage-y += cbmem.c +romstage-y += boot.c + +romstage-y += cbfs_and_run.c +romstage-$(CONFIG_ARCH_RAMSTAGE_X86_32) += cpu_common.c +romstage-y += memset.c +romstage-y += memcpy.c +romstage-y += memmove.c +romstage-y += mmap_boot.c + +romstage-$(CONFIG_COLLECT_TIMESTAMPS) += timestamp.c + +endif # CONFIG_ARCH_ROMSTAGE_X86_32 / CONFIG_ARCH_ROMSTAGE_X86_64 + +ifeq ($(CONFIG_ARCH_RAMSTAGE_X86_32)$(CONFIG_ARCH_RAMSTAGE_X86_64),y) + +ramstage-y += boot.c +ramstage-y += gdt.c +ramstage-y += tables.c +ramstage-y += cbmem.c +ramstage-$(CONFIG_GENERATE_MP_TABLE) += mpspec.c +ramstage-$(CONFIG_GENERATE_PIRQ_TABLE) += pirq_routing.c +ramstage-$(CONFIG_HAVE_ACPI_TABLES) += acpi.c +ramstage-$(CONFIG_GENERATE_SMBIOS_TABLES) += smbios.c +ramstage-$(CONFIG_HAVE_ACPI_TABLES) += acpigen.c +ramstage-$(CONFIG_HAVE_ACPI_RESUME) += wakeup.S + +ramstage-y += c_start.S +ramstage-y += cpu.c +ramstage-y += cpu_common.c +ramstage-y += pci_ops_conf1.c +ramstage-$(CONFIG_MMCONF_SUPPORT) += pci_ops_mmconf.c +ramstage-y += exception.c +ramstage-$(CONFIG_IOAPIC) += ioapic.c +ramstage-y += memset.c +ramstage-y += memcpy.c +ramstage-y += memmove.c +ramstage-y += ebda.c +ramstage-y += mmap_boot.c +ramstage-$(CONFIG_COOP_MULTITASKING) += thread.c +ramstage-$(CONFIG_COOP_MULTITASKING) += thread_switch.S +ramstage-$(CONFIG_COLLECT_TIMESTAMPS) += timestamp.c + +smm-y += memset.c +smm-y += memcpy.c +smm-y += memmove.c +smm-y += mmap_boot.c + +ifeq ($(CONFIG_ARCH_RAMSTAGE_X86_32),y) +rmodules_x86_32-y += memset.c +rmodules_x86_32-y += memcpy.c +rmodules_x86_32-y += memmove.c +else +rmodules_x86_64-y += memset.c +rmodules_x86_64-y += memcpy.c +rmodules_x86_64-y += memmove.c +endif + +endif # CONFIG_ARCH_RAMSTAGE_X86_32 / CONFIG_ARCH_RAMSTAGE_X86_64 diff --git a/src/arch/x86/acpi.c b/src/arch/x86/acpi.c new file mode 100644 index 0000000000..134e43782e --- /dev/null +++ b/src/arch/x86/acpi.c @@ -0,0 +1,1137 @@ +/* + * This file is part of the coreboot project. + * + * coreboot ACPI Table support + * written by Stefan Reinauer + * + * Copyright (C) 2004 SUSE LINUX AG + * Copyright (C) 2005-2009 coresystems GmbH + * + * ACPI FADT, FACS, and DSDT table support added by + * Nick Barker , and those portions + * Copyright (C) 2004 Nick Barker + * + * Copyright (C) 2005 ADVANCED MICRO DEVICES, INC. All Rights Reserved. + * 2005.9 yhlu add SRAT table generation + */ + +/* + * Each system port implementing ACPI has to provide two functions: + * + * write_acpi_tables() + * acpi_dump_apics() + * + * See Kontron 986LCD-M port for a good example of an ACPI implementation + * in coreboot. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/* FIXME: Kconfig doesn't support overridable defaults :-( */ +#ifndef CONFIG_HPET_MIN_TICKS +#define CONFIG_HPET_MIN_TICKS 0x1000 +#endif + +u8 acpi_checksum(u8 *table, u32 length) +{ + u8 ret = 0; + while (length--) { + ret += *table; + table++; + } + return -ret; +} + +/** + * Add an ACPI table to the RSDT (and XSDT) structure, recalculate length + * and checksum. + */ +void acpi_add_table(acpi_rsdp_t *rsdp, void *table) +{ + int i, entries_num; + acpi_rsdt_t *rsdt; + acpi_xsdt_t *xsdt = NULL; + + /* The RSDT is mandatory... */ + rsdt = (acpi_rsdt_t *)(uintptr_t)rsdp->rsdt_address; + + /* ...while the XSDT is not. */ + if (rsdp->xsdt_address) + xsdt = (acpi_xsdt_t *)((uintptr_t)rsdp->xsdt_address); + + /* This should always be MAX_ACPI_TABLES. */ + entries_num = ARRAY_SIZE(rsdt->entry); + + for (i = 0; i < entries_num; i++) { + if (rsdt->entry[i] == 0) + break; + } + + if (i >= entries_num) { + printk(BIOS_ERR, "ACPI: Error: Could not add ACPI table, " + "too many tables.\n"); + return; + } + + /* Add table to the RSDT. */ + rsdt->entry[i] = (uintptr_t)table; + + /* Fix RSDT length or the kernel will assume invalid entries. */ + rsdt->header.length = sizeof(acpi_header_t) + (sizeof(u32) * (i + 1)); + + /* Re-calculate checksum. */ + rsdt->header.checksum = 0; /* Hope this won't get optimized away */ + rsdt->header.checksum = acpi_checksum((u8 *)rsdt, rsdt->header.length); + + /* + * And now the same thing for the XSDT. We use the same index as for + * now we want the XSDT and RSDT to always be in sync in coreboot. + */ + if (xsdt) { + /* Add table to the XSDT. */ + xsdt->entry[i] = (u64)(uintptr_t)table; + + /* Fix XSDT length. */ + xsdt->header.length = sizeof(acpi_header_t) + + (sizeof(u64) * (i + 1)); + + /* Re-calculate checksum. */ + xsdt->header.checksum = 0; + xsdt->header.checksum = acpi_checksum((u8 *)xsdt, + xsdt->header.length); + } + + printk(BIOS_DEBUG, "ACPI: added table %d/%d, length now %d\n", + i + 1, entries_num, rsdt->header.length); +} + +int acpi_create_mcfg_mmconfig(acpi_mcfg_mmconfig_t *mmconfig, u32 base, + u16 seg_nr, u8 start, u8 end) +{ + memset(mmconfig, 0, sizeof(*mmconfig)); + mmconfig->base_address = base; + mmconfig->base_reserved = 0; + mmconfig->pci_segment_group_number = seg_nr; + mmconfig->start_bus_number = start; + mmconfig->end_bus_number = end; + + return sizeof(acpi_mcfg_mmconfig_t); +} + +int acpi_create_madt_lapic(acpi_madt_lapic_t *lapic, u8 cpu, u8 apic) +{ + lapic->type = 0; /* Local APIC structure */ + lapic->length = sizeof(acpi_madt_lapic_t); + lapic->flags = (1 << 0); /* Processor/LAPIC enabled */ + lapic->processor_id = cpu; + lapic->apic_id = apic; + + return lapic->length; +} + +unsigned long acpi_create_madt_lapics(unsigned long current) +{ + struct device *cpu; + int index = 0; + + for (cpu = all_devices; cpu; cpu = cpu->next) { + if ((cpu->path.type != DEVICE_PATH_APIC) || + (cpu->bus->dev->path.type != DEVICE_PATH_CPU_CLUSTER)) { + continue; + } + if (!cpu->enabled) + continue; + current += acpi_create_madt_lapic((acpi_madt_lapic_t *)current, + index, cpu->path.apic.apic_id); + index++; + } + + return current; +} + +int acpi_create_madt_ioapic(acpi_madt_ioapic_t *ioapic, u8 id, u32 addr, + u32 gsi_base) +{ + ioapic->type = 1; /* I/O APIC structure */ + ioapic->length = sizeof(acpi_madt_ioapic_t); + ioapic->reserved = 0x00; + ioapic->gsi_base = gsi_base; + ioapic->ioapic_id = id; + ioapic->ioapic_addr = addr; + + return ioapic->length; +} + +int acpi_create_madt_irqoverride(acpi_madt_irqoverride_t *irqoverride, + u8 bus, u8 source, u32 gsirq, u16 flags) +{ + irqoverride->type = 2; /* Interrupt source override */ + irqoverride->length = sizeof(acpi_madt_irqoverride_t); + irqoverride->bus = bus; + irqoverride->source = source; + irqoverride->gsirq = gsirq; + irqoverride->flags = flags; + + return irqoverride->length; +} + +int acpi_create_madt_lapic_nmi(acpi_madt_lapic_nmi_t *lapic_nmi, u8 cpu, + u16 flags, u8 lint) +{ + lapic_nmi->type = 4; /* Local APIC NMI structure */ + lapic_nmi->length = sizeof(acpi_madt_lapic_nmi_t); + lapic_nmi->flags = flags; + lapic_nmi->processor_id = cpu; + lapic_nmi->lint = lint; + + return lapic_nmi->length; +} + +void acpi_create_madt(acpi_madt_t *madt) +{ + acpi_header_t *header = &(madt->header); + unsigned long current = (unsigned long)madt + sizeof(acpi_madt_t); + + memset((void *)madt, 0, sizeof(acpi_madt_t)); + + /* Fill out header fields. */ + memcpy(header->signature, "APIC", 4); + memcpy(header->oem_id, OEM_ID, 6); + memcpy(header->oem_table_id, ACPI_TABLE_CREATOR, 8); + memcpy(header->asl_compiler_id, ASLC, 4); + + header->length = sizeof(acpi_madt_t); + header->revision = 1; /* ACPI 1.0/2.0: 1, ACPI 3.0: 2, ACPI 4.0: 3 */ + + madt->lapic_addr = LOCAL_APIC_ADDR; + madt->flags = 0x1; /* PCAT_COMPAT */ + + current = acpi_fill_madt(current); + + /* (Re)calculate length and checksum. */ + header->length = current - (unsigned long)madt; + + header->checksum = acpi_checksum((void *)madt, header->length); +} + +/* MCFG is defined in the PCI Firmware Specification 3.0. */ +void acpi_create_mcfg(acpi_mcfg_t *mcfg) +{ + acpi_header_t *header = &(mcfg->header); + unsigned long current = (unsigned long)mcfg + sizeof(acpi_mcfg_t); + + memset((void *)mcfg, 0, sizeof(acpi_mcfg_t)); + + /* Fill out header fields. */ + memcpy(header->signature, "MCFG", 4); + memcpy(header->oem_id, OEM_ID, 6); + memcpy(header->oem_table_id, ACPI_TABLE_CREATOR, 8); + memcpy(header->asl_compiler_id, ASLC, 4); + + header->length = sizeof(acpi_mcfg_t); + header->revision = 1; + + current = acpi_fill_mcfg(current); + + /* (Re)calculate length and checksum. */ + header->length = current - (unsigned long)mcfg; + header->checksum = acpi_checksum((void *)mcfg, header->length); +} + +static void *get_tcpa_log(u32 *size) +{ + const struct cbmem_entry *ce; + const u32 tcpa_default_log_len = 0x10000; + void *lasa; + ce = cbmem_entry_find(CBMEM_ID_TCPA_LOG); + if (ce) { + lasa = cbmem_entry_start(ce); + *size = cbmem_entry_size(ce); + printk(BIOS_DEBUG, "TCPA log found at %p\n", lasa); + return lasa; + } + lasa = cbmem_add(CBMEM_ID_TCPA_LOG, tcpa_default_log_len); + if (!lasa) { + printk(BIOS_ERR, "TCPA log creation failed\n"); + return NULL; + } + + printk(BIOS_DEBUG, "TCPA log created at %p\n", lasa); + memset (lasa, 0, tcpa_default_log_len); + + *size = tcpa_default_log_len; + return lasa; +} + +static void acpi_create_tcpa(acpi_tcpa_t *tcpa) +{ + acpi_header_t *header = &(tcpa->header); + u32 tcpa_log_len; + void *lasa; + + memset((void *)tcpa, 0, sizeof(acpi_tcpa_t)); + + lasa = get_tcpa_log(&tcpa_log_len); + if (!lasa) { + return; + } + + /* Fill out header fields. */ + memcpy(header->signature, "TCPA", 4); + memcpy(header->oem_id, OEM_ID, 6); + memcpy(header->oem_table_id, ACPI_TABLE_CREATOR, 8); + memcpy(header->asl_compiler_id, ASLC, 4); + + header->length = sizeof(acpi_tcpa_t); + header->revision = 2; + + tcpa->platform_class = 0; + tcpa->laml = tcpa_log_len; + tcpa->lasa = (uintptr_t) lasa; + + /* Calculate checksum. */ + header->checksum = acpi_checksum((void *)tcpa, header->length); +} + +void acpi_create_ssdt_generator(acpi_header_t *ssdt, const char *oem_table_id) +{ + unsigned long current = (unsigned long)ssdt + sizeof(acpi_header_t); + + memset((void *)ssdt, 0, sizeof(acpi_header_t)); + + memcpy(&ssdt->signature, "SSDT", 4); + ssdt->revision = 2; /* ACPI 1.0/2.0: ?, ACPI 3.0/4.0: 2 */ + memcpy(&ssdt->oem_id, OEM_ID, 6); + memcpy(&ssdt->oem_table_id, oem_table_id, 8); + ssdt->oem_revision = 42; + memcpy(&ssdt->asl_compiler_id, ASLC, 4); + ssdt->asl_compiler_revision = 42; + ssdt->length = sizeof(acpi_header_t); + + acpigen_set_current((char *) current); + { + struct device *dev; + for (dev = all_devices; dev; dev = dev->next) + if (dev->ops && dev->ops->acpi_fill_ssdt_generator) { + dev->ops->acpi_fill_ssdt_generator(dev); + } + current = (unsigned long) acpigen_get_current(); + } + + /* (Re)calculate length and checksum. */ + ssdt->length = current - (unsigned long)ssdt; + ssdt->checksum = acpi_checksum((void *)ssdt, ssdt->length); +} + +int acpi_create_srat_lapic(acpi_srat_lapic_t *lapic, u8 node, u8 apic) +{ + memset((void *)lapic, 0, sizeof(acpi_srat_lapic_t)); + + lapic->type = 0; /* Processor local APIC/SAPIC affinity structure */ + lapic->length = sizeof(acpi_srat_lapic_t); + lapic->flags = (1 << 0); /* Enabled (the use of this structure). */ + lapic->proximity_domain_7_0 = node; + /* TODO: proximity_domain_31_8, local SAPIC EID, clock domain. */ + lapic->apic_id = apic; + + return lapic->length; +} + +int acpi_create_srat_mem(acpi_srat_mem_t *mem, u8 node, u32 basek, u32 sizek, + u32 flags) +{ + mem->type = 1; /* Memory affinity structure */ + mem->length = sizeof(acpi_srat_mem_t); + mem->base_address_low = (basek << 10); + mem->base_address_high = (basek >> (32 - 10)); + mem->length_low = (sizek << 10); + mem->length_high = (sizek >> (32 - 10)); + mem->proximity_domain = node; + mem->flags = flags; + + return mem->length; +} + +/* http://www.microsoft.com/whdc/system/sysinternals/sratdwn.mspx */ +void acpi_create_srat(acpi_srat_t *srat, + unsigned long (*acpi_fill_srat)(unsigned long current)) +{ + acpi_header_t *header = &(srat->header); + unsigned long current = (unsigned long)srat + sizeof(acpi_srat_t); + + memset((void *)srat, 0, sizeof(acpi_srat_t)); + + /* Fill out header fields. */ + memcpy(header->signature, "SRAT", 4); + memcpy(header->oem_id, OEM_ID, 6); + memcpy(header->oem_table_id, ACPI_TABLE_CREATOR, 8); + memcpy(header->asl_compiler_id, ASLC, 4); + + header->length = sizeof(acpi_srat_t); + header->revision = 1; /* ACPI 1.0: N/A, 2.0: 1, 3.0: 2, 4.0: 3 */ + + srat->resv = 1; /* Spec: Reserved to 1 for backwards compatibility. */ + + current = acpi_fill_srat(current); + + /* (Re)calculate length and checksum. */ + header->length = current - (unsigned long)srat; + header->checksum = acpi_checksum((void *)srat, header->length); +} + +void acpi_create_dmar(acpi_dmar_t *dmar, + unsigned long (*acpi_fill_dmar) (unsigned long)) +{ + acpi_header_t *header = &(dmar->header); + unsigned long current = (unsigned long)dmar + sizeof(acpi_dmar_t); + + memset((void *)dmar, 0, sizeof(acpi_dmar_t)); + + /* Fill out header fields. */ + memcpy(header->signature, "DMAR", 4); + memcpy(header->oem_id, OEM_ID, 6); + memcpy(header->oem_table_id, ACPI_TABLE_CREATOR, 8); + memcpy(header->asl_compiler_id, ASLC, 4); + + header->length = sizeof(acpi_dmar_t); + header->revision = 1; + + dmar->host_address_width = 40 - 1; /* FIXME: == MTRR size? */ + dmar->flags = 0; + + current = acpi_fill_dmar(current); + + /* (Re)calculate length and checksum. */ + header->length = current - (unsigned long)dmar; + header->checksum = acpi_checksum((void *)dmar, header->length); +} + +unsigned long acpi_create_dmar_drhd(unsigned long current, u8 flags, + u16 segment, u32 bar) +{ + dmar_entry_t *drhd = (dmar_entry_t *)current; + memset(drhd, 0, sizeof(*drhd)); + drhd->type = DMAR_DRHD; + drhd->length = sizeof(*drhd); /* will be fixed up later */ + drhd->flags = flags; + drhd->segment = segment; + drhd->bar = bar; + + return drhd->length; +} + +void acpi_dmar_drhd_fixup(unsigned long base, unsigned long current) +{ + dmar_entry_t *drhd = (dmar_entry_t *)base; + drhd->length = current - base; +} + +unsigned long acpi_create_dmar_drhd_ds_pci(unsigned long current, u8 segment, + u8 dev, u8 fn) +{ + dev_scope_t *ds = (dev_scope_t *)current; + memset(ds, 0, sizeof(*ds)); + ds->type = SCOPE_PCI_ENDPOINT; + ds->length = sizeof(*ds) + 2; /* we don't support longer paths yet */ + ds->start_bus = segment; + ds->path[0].dev = dev; + ds->path[0].fn = fn; + + return ds->length; +} + +/* http://h21007.www2.hp.com/portal/download/files/unprot/Itanium/slit.pdf */ +void acpi_create_slit(acpi_slit_t *slit, + unsigned long (*acpi_fill_slit)(unsigned long current)) +{ + acpi_header_t *header = &(slit->header); + unsigned long current = (unsigned long)slit + sizeof(acpi_slit_t); + + memset((void *)slit, 0, sizeof(acpi_slit_t)); + + /* Fill out header fields. */ + memcpy(header->signature, "SLIT", 4); + memcpy(header->oem_id, OEM_ID, 6); + memcpy(header->oem_table_id, ACPI_TABLE_CREATOR, 8); + memcpy(header->asl_compiler_id, ASLC, 4); + + header->length = sizeof(acpi_slit_t); + header->revision = 1; /* ACPI 1.0: N/A, ACPI 2.0/3.0/4.0: 1 */ + + current = acpi_fill_slit(current); + + /* (Re)calculate length and checksum. */ + header->length = current - (unsigned long)slit; + header->checksum = acpi_checksum((void *)slit, header->length); +} + +/* http://www.intel.com/hardwaredesign/hpetspec_1.pdf */ +void acpi_create_hpet(acpi_hpet_t *hpet) +{ + acpi_header_t *header = &(hpet->header); + acpi_addr_t *addr = &(hpet->addr); + + memset((void *)hpet, 0, sizeof(acpi_hpet_t)); + + /* Fill out header fields. */ + memcpy(header->signature, "HPET", 4); + memcpy(header->oem_id, OEM_ID, 6); + memcpy(header->oem_table_id, ACPI_TABLE_CREATOR, 8); + memcpy(header->asl_compiler_id, ASLC, 4); + + header->length = sizeof(acpi_hpet_t); + header->revision = 1; /* Currently 1. Table added in ACPI 2.0. */ + + /* Fill out HPET address. */ + addr->space_id = 0; /* Memory */ + addr->bit_width = 64; + addr->bit_offset = 0; + addr->addrl = CONFIG_HPET_ADDRESS & 0xffffffff; + addr->addrh = ((unsigned long long)CONFIG_HPET_ADDRESS) >> 32; + + hpet->id = *(unsigned int*)CONFIG_HPET_ADDRESS; + hpet->number = 0; + hpet->min_tick = CONFIG_HPET_MIN_TICKS; + + header->checksum = acpi_checksum((void *)hpet, sizeof(acpi_hpet_t)); +} + +unsigned long acpi_write_hpet(device_t device, unsigned long current, acpi_rsdp_t *rsdp) +{ + acpi_hpet_t *hpet; + + /* + * We explicitly add these tables later on: + */ + printk(BIOS_DEBUG, "ACPI: * HPET\n"); + + hpet = (acpi_hpet_t *) current; + current += sizeof(acpi_hpet_t); + current = ALIGN(current, 16); + acpi_create_hpet(hpet); + acpi_add_table(rsdp, hpet); + + return current; +} + +void acpi_create_facs(acpi_facs_t *facs) +{ + memset((void *)facs, 0, sizeof(acpi_facs_t)); + + memcpy(facs->signature, "FACS", 4); + facs->length = sizeof(acpi_facs_t); + facs->hardware_signature = 0; + facs->firmware_waking_vector = 0; + facs->global_lock = 0; + facs->flags = 0; + facs->x_firmware_waking_vector_l = 0; + facs->x_firmware_waking_vector_h = 0; + facs->version = 1; /* ACPI 1.0: 0, ACPI 2.0/3.0: 1, ACPI 4.0: 2 */ +} + +static void acpi_write_rsdt(acpi_rsdt_t *rsdt, char *oem_id, char *oem_table_id) +{ + acpi_header_t *header = &(rsdt->header); + + /* Fill out header fields. */ + memcpy(header->signature, "RSDT", 4); + memcpy(header->oem_id, oem_id, 6); + memcpy(header->oem_table_id, oem_table_id, 8); + memcpy(header->asl_compiler_id, ASLC, 4); + + header->length = sizeof(acpi_rsdt_t); + header->revision = 1; /* ACPI 1.0/2.0/3.0/4.0: 1 */ + + /* Entries are filled in later, we come with an empty set. */ + + /* Fix checksum. */ + header->checksum = acpi_checksum((void *)rsdt, sizeof(acpi_rsdt_t)); +} + +static void acpi_write_xsdt(acpi_xsdt_t *xsdt, char *oem_id, char *oem_table_id) +{ + acpi_header_t *header = &(xsdt->header); + + /* Fill out header fields. */ + memcpy(header->signature, "XSDT", 4); + memcpy(header->oem_id, oem_id, 6); + memcpy(header->oem_table_id, oem_table_id, 8); + memcpy(header->asl_compiler_id, ASLC, 4); + + header->length = sizeof(acpi_xsdt_t); + header->revision = 1; /* ACPI 1.0: N/A, 2.0/3.0/4.0: 1 */ + + /* Entries are filled in later, we come with an empty set. */ + + /* Fix checksum. */ + header->checksum = acpi_checksum((void *)xsdt, sizeof(acpi_xsdt_t)); +} + +static void acpi_write_rsdp(acpi_rsdp_t *rsdp, acpi_rsdt_t *rsdt, + acpi_xsdt_t *xsdt, char *oem_id) +{ + memset(rsdp, 0, sizeof(acpi_rsdp_t)); + + memcpy(rsdp->signature, RSDP_SIG, 8); + memcpy(rsdp->oem_id, oem_id, 6); + + rsdp->length = sizeof(acpi_rsdp_t); + rsdp->rsdt_address = (uintptr_t)rsdt; + + /* + * Revision: ACPI 1.0: 0, ACPI 2.0/3.0/4.0: 2. + * + * Some OSes expect an XSDT to be present for RSD PTR revisions >= 2. + * If we don't have an ACPI XSDT, force ACPI 1.0 (and thus RSD PTR + * revision 0). + */ + if (xsdt == NULL) { + rsdp->revision = 0; + } else { + rsdp->xsdt_address = (u64)(uintptr_t)xsdt; + rsdp->revision = 2; + } + + /* Calculate checksums. */ + rsdp->checksum = acpi_checksum((void *)rsdp, 20); + rsdp->ext_checksum = acpi_checksum((void *)rsdp, sizeof(acpi_rsdp_t)); +} + +unsigned long acpi_create_hest_error_source(acpi_hest_t *hest, acpi_hest_esd_t *esd, u16 type, void *data, u16 data_len) +{ + acpi_header_t *header = &(hest->header); + acpi_hest_hen_t *hen; + void *pos; + u16 len; + + pos = esd; + memset(pos, 0, sizeof(acpi_hest_esd_t)); + len = 0; + esd->type = type; /* MCE */ + esd->source_id = hest->error_source_count; + esd->flags = 0; /* FIRMWARE_FIRST */ + esd->enabled = 1; + esd->prealloc_erecords = 1; + esd->max_section_per_record = 0x1; + + len += sizeof(acpi_hest_esd_t); + pos = esd + 1; + + switch (type) { + case 0: /* MCE */ + break; + case 1: /* CMC */ + hen = (acpi_hest_hen_t *) (pos); + memset(pos, 0, sizeof(acpi_hest_hen_t)); + hen->type = 3; /* SCI? */ + hen->length = sizeof(acpi_hest_hen_t); + hen->conf_we = 0; /* Configuration Write Enable. */ + hen->poll_interval = 0; + hen->vector = 0; + hen->sw2poll_threshold_val = 0; + hen->sw2poll_threshold_win = 0; + hen->error_threshold_val = 0; + hen->error_threshold_win = 0; + len += sizeof(acpi_hest_hen_t); + pos = hen + 1; + break; + case 2: /* NMI */ + case 6: /* AER Root Port */ + case 7: /* AER Endpoint */ + case 8: /* AER Bridge */ + case 9: /* Generic Hardware Error Source. */ + /* TODO: */ + break; + default: + printk(BIOS_DEBUG, "Invalid type of Error Source."); + break; + } + hest->error_source_count ++; + + memcpy(pos, data, data_len); + len += data_len; + header->length += len; + + return len; +} + +/* ACPI 4.0 */ +void acpi_write_hest(acpi_hest_t *hest, + unsigned long (*acpi_fill_hest)(acpi_hest_t *hest)) +{ + acpi_header_t *header = &(hest->header); + + memset(hest, 0, sizeof(acpi_hest_t)); + + memcpy(header->signature, "HEST", 4); + memcpy(header->oem_id, OEM_ID, 6); + memcpy(header->oem_table_id, ACPI_TABLE_CREATOR, 8); + memcpy(header->asl_compiler_id, ASLC, 4); + header->length += sizeof(acpi_hest_t); + header->revision = 1; + + acpi_fill_hest(hest); + + /* Calculate checksums. */ + header->checksum = acpi_checksum((void *)hest, header->length); +} + +#if IS_ENABLED(CONFIG_COMMON_FADT) +void acpi_create_fadt(acpi_fadt_t *fadt,acpi_facs_t *facs, void *dsdt) +{ + acpi_header_t *header = &(fadt->header); + + memset((void *) fadt, 0, sizeof(acpi_fadt_t)); + memcpy(header->signature, "FACP", 4); + header->length = sizeof(acpi_fadt_t); + header->revision = 4; + memcpy(header->oem_id, OEM_ID, 6); + memcpy(header->oem_table_id, ACPI_TABLE_CREATOR, 8); + memcpy(header->asl_compiler_id, ASLC, 4); + header->asl_compiler_revision = 0; + + fadt->firmware_ctrl = (unsigned long) facs; + fadt->dsdt = (unsigned long) dsdt; + + fadt->x_firmware_ctl_l = (unsigned long)facs; + fadt->x_firmware_ctl_h = 0; + fadt->x_dsdt_l = (unsigned long)dsdt; + fadt->x_dsdt_h = 0; + + if(IS_ENABLED(CONFIG_SYSTEM_TYPE_LAPTOP)) { + fadt->preferred_pm_profile = PM_MOBILE; + } else { + fadt->preferred_pm_profile = PM_DESKTOP; + } + + acpi_fill_fadt(fadt); + + header->checksum = + acpi_checksum((void *) fadt, header->length); +} +#endif + +unsigned long __attribute__ ((weak)) fw_cfg_acpi_tables(unsigned long start) +{ + return 0; +} + +#define ALIGN_CURRENT current = (ALIGN(current, 16)) +unsigned long write_acpi_tables(unsigned long start) +{ + unsigned long current; + acpi_rsdp_t *rsdp; + acpi_rsdt_t *rsdt; + acpi_xsdt_t *xsdt; + acpi_fadt_t *fadt; + acpi_facs_t *facs; + acpi_header_t *slic_file, *slic; + acpi_header_t *ssdt; + acpi_header_t *dsdt_file, *dsdt; + acpi_mcfg_t *mcfg; + acpi_tcpa_t *tcpa; + acpi_madt_t *madt; + struct device *dev; + unsigned long fw; + size_t slic_size, dsdt_size; + char oem_id[6], oem_table_id[8]; + + current = start; + + /* Align ACPI tables to 16byte */ + ALIGN_CURRENT; + + fw = fw_cfg_acpi_tables(current); + if (fw) + return fw; + +#if CONFIG_COMPILE_IN_DSDT + extern char _binary_dsdt_aml_start; + extern char _binary_dsdt_aml_end; + dsdt_file = (acpi_header_t *)&_binary_dsdt_aml_start; + dsdt_size = (size_t)(&_binary_dsdt_aml_end - &_binary_dsdt_aml_start); +#else + dsdt_file = cbfs_boot_map_with_leak( + CONFIG_CBFS_PREFIX "/dsdt.aml", + CBFS_TYPE_RAW, &dsdt_size); +#endif + if (!dsdt_file) { + printk(BIOS_ERR, "No DSDT file, skipping ACPI tables\n"); + return current; + } + + if (dsdt_file->length > dsdt_size + || dsdt_file->length < sizeof (acpi_header_t) + || memcmp(dsdt_file->signature, "DSDT", 4) != 0) { + printk(BIOS_ERR, "Invalid DSDT file, skipping ACPI tables\n"); + return current; + } + + slic_file = cbfs_boot_map_with_leak(CONFIG_CBFS_PREFIX "/slic", + CBFS_TYPE_RAW, &slic_size); + if (slic_file + && (slic_file->length > slic_size + || slic_file->length < sizeof (acpi_header_t) + || memcmp(slic_file->signature, "SLIC", 4) != 0)) { + slic_file = 0; + } + + if (slic_file) { + memcpy(oem_id, slic_file->oem_id, 6); + memcpy(oem_table_id, slic_file->oem_table_id, 8); + } else { + memcpy(oem_id, OEM_ID, 6); + memcpy(oem_table_id, ACPI_TABLE_CREATOR, 8); + } + + printk(BIOS_INFO, "ACPI: Writing ACPI tables at %lx.\n", start); + + /* We need at least an RSDP and an RSDT Table */ + rsdp = (acpi_rsdp_t *) current; + current += sizeof(acpi_rsdp_t); + ALIGN_CURRENT; + rsdt = (acpi_rsdt_t *) current; + current += sizeof(acpi_rsdt_t); + ALIGN_CURRENT; + xsdt = (acpi_xsdt_t *) current; + current += sizeof(acpi_xsdt_t); + ALIGN_CURRENT; + + /* clear all table memory */ + memset((void *) start, 0, current - start); + + acpi_write_rsdp(rsdp, rsdt, xsdt, oem_id); + acpi_write_rsdt(rsdt, oem_id, oem_table_id); + acpi_write_xsdt(xsdt, oem_id, oem_table_id); + + printk(BIOS_DEBUG, "ACPI: * FACS\n"); + facs = (acpi_facs_t *) current; + current += sizeof(acpi_facs_t); + ALIGN_CURRENT; + acpi_create_facs(facs); + + printk(BIOS_DEBUG, "ACPI: * DSDT\n"); + dsdt = (acpi_header_t *) current; + memcpy(dsdt, dsdt_file, sizeof(acpi_header_t)); + if (dsdt->length >= sizeof(acpi_header_t)) { + current += sizeof(acpi_header_t); + + acpigen_set_current((char *) current); + for (dev = all_devices; dev; dev = dev->next) + if (dev->ops && dev->ops->acpi_inject_dsdt_generator) { + dev->ops->acpi_inject_dsdt_generator(dev); + } + current = (unsigned long) acpigen_get_current(); + memcpy((char *)current, + (char *)dsdt_file + sizeof(acpi_header_t), + dsdt->length - sizeof(acpi_header_t)); + current += dsdt->length - sizeof(acpi_header_t); + + /* (Re)calculate length and checksum. */ + dsdt->length = current - (unsigned long)dsdt; + dsdt->checksum = 0; + dsdt->checksum = acpi_checksum((void *)dsdt, dsdt->length); + } + + ALIGN_CURRENT; + + printk(BIOS_DEBUG, "ACPI: * FADT\n"); + fadt = (acpi_fadt_t *) current; + current += sizeof(acpi_fadt_t); + ALIGN_CURRENT; + + acpi_create_fadt(fadt, facs, dsdt); + acpi_add_table(rsdp, fadt); + + if (slic_file) { + printk(BIOS_DEBUG, "ACPI: * SLIC\n"); + slic = (acpi_header_t *)current; + memcpy(slic, slic_file, slic_file->length); + current += slic_file->length; + ALIGN_CURRENT; + acpi_add_table(rsdp, slic); + } + + printk(BIOS_DEBUG, "ACPI: * SSDT\n"); + ssdt = (acpi_header_t *)current; + acpi_create_ssdt_generator(ssdt, ACPI_TABLE_CREATOR); + if (ssdt->length > sizeof(acpi_header_t)) { + current += ssdt->length; + acpi_add_table(rsdp, ssdt); + ALIGN_CURRENT; + } + + printk(BIOS_DEBUG, "ACPI: * MCFG\n"); + mcfg = (acpi_mcfg_t *) current; + acpi_create_mcfg(mcfg); + if (mcfg->header.length > sizeof(acpi_mcfg_t)) { + current += mcfg->header.length; + ALIGN_CURRENT; + acpi_add_table(rsdp, mcfg); + } + + printk(BIOS_DEBUG, "ACPI: * TCPA\n"); + tcpa = (acpi_tcpa_t *) current; + acpi_create_tcpa(tcpa); + if (tcpa->header.length >= sizeof(acpi_tcpa_t)) { + current += tcpa->header.length; + ALIGN_CURRENT; + acpi_add_table(rsdp, tcpa); + } + + printk(BIOS_DEBUG, "ACPI: * MADT\n"); + + madt = (acpi_madt_t *) current; + acpi_create_madt(madt); + if (madt->header.length > sizeof(acpi_madt_t)) { + current+=madt->header.length; + acpi_add_table(rsdp,madt); + } + ALIGN_CURRENT; + + printk(BIOS_DEBUG, "current = %lx\n", current); + + for (dev = all_devices; dev; dev = dev->next) { + if (dev->ops && dev->ops->write_acpi_tables) { + current = dev->ops->write_acpi_tables(dev, current, rsdp); + ALIGN_CURRENT; + } + } + + printk(BIOS_INFO, "ACPI: done.\n"); + return current; +} + +#if CONFIG_HAVE_ACPI_RESUME +void __attribute__((weak)) mainboard_suspend_resume(void) +{ +} + +void acpi_resume(void *wake_vec) +{ +#if CONFIG_HAVE_SMI_HANDLER + u32 *gnvs_address = cbmem_find(CBMEM_ID_ACPI_GNVS_PTR); + + /* Restore GNVS pointer in SMM if found */ + if (gnvs_address && *gnvs_address) { + printk(BIOS_DEBUG, "Restore GNVS pointer to 0x%08x\n", + *gnvs_address); + smm_setup_structures((void *)*gnvs_address, NULL, NULL); + } +#endif + + /* Call mainboard resume handler first, if defined. */ + mainboard_suspend_resume(); + + post_code(POST_OS_RESUME); + acpi_jump_to_wakeup(wake_vec); +} + +/* This is filled with acpi_is_wakeup() call early in ramstage. */ +int acpi_slp_type = -1; + +#if IS_ENABLED(CONFIG_EARLY_CBMEM_INIT) +int acpi_get_sleep_type(void) +{ + struct romstage_handoff *handoff; + + handoff = cbmem_find(CBMEM_ID_ROMSTAGE_INFO); + + if (handoff == NULL) { + printk(BIOS_DEBUG, "Unknown boot method, assuming normal.\n"); + return 0; + } else if (handoff->s3_resume) { + printk(BIOS_DEBUG, "S3 Resume.\n"); + return 3; + } else { + printk(BIOS_DEBUG, "Normal boot.\n"); + return 0; + } +} +#endif + +static void acpi_handoff_wakeup(void) +{ + if (acpi_slp_type < 0) + acpi_slp_type = acpi_get_sleep_type(); +} + +int acpi_is_wakeup(void) +{ + acpi_handoff_wakeup(); + /* Both resume from S2 and resume from S3 restart at CPU reset */ + return (acpi_slp_type == 3 || acpi_slp_type == 2); +} + +int acpi_is_wakeup_s3(void) +{ + acpi_handoff_wakeup(); + return (acpi_slp_type == 3); +} + +void acpi_fail_wakeup(void) +{ + if (acpi_slp_type == 3 || acpi_slp_type == 2) + acpi_slp_type = 0; +} + +void acpi_prepare_resume_backup(void) +{ + if (!acpi_s3_resume_allowed()) + return; + + /* Let's prepare the ACPI S3 Resume area now already, so we can rely on + * it being there during reboot time. We don't need the pointer, nor + * the result right now. If it fails, ACPI resume will be disabled. + */ + + if (HIGH_MEMORY_SAVE) + cbmem_add(CBMEM_ID_RESUME, HIGH_MEMORY_SAVE); +} + +static acpi_rsdp_t *valid_rsdp(acpi_rsdp_t *rsdp) +{ + if (strncmp((char *)rsdp, RSDP_SIG, sizeof(RSDP_SIG) - 1) != 0) + return NULL; + + printk(BIOS_DEBUG, "Looking on %p for valid checksum\n", rsdp); + + if (acpi_checksum((void *)rsdp, 20) != 0) + return NULL; + printk(BIOS_DEBUG, "Checksum 1 passed\n"); + + if ((rsdp->revision > 1) && (acpi_checksum((void *)rsdp, + rsdp->length) != 0)) + return NULL; + printk(BIOS_DEBUG, "Checksum 2 passed all OK\n"); + + return rsdp; +} + +static acpi_rsdp_t *rsdp; + +void *acpi_get_wakeup_rsdp(void) +{ + return rsdp; +} + +void *acpi_find_wakeup_vector(void) +{ + char *p, *end; + acpi_rsdt_t *rsdt; + acpi_facs_t *facs; + acpi_fadt_t *fadt = NULL; + void *wake_vec; + int i; + + rsdp = NULL; + + if (!acpi_is_wakeup()) + return NULL; + + printk(BIOS_DEBUG, "Trying to find the wakeup vector...\n"); + + /* Find RSDP. */ + for (p = (char *)0xe0000; p < (char *)0xfffff; p += 16) { + if ((rsdp = valid_rsdp((acpi_rsdp_t *)p))) + break; + } + + if (rsdp == NULL) + return NULL; + + printk(BIOS_DEBUG, "RSDP found at %p\n", rsdp); + rsdt = (acpi_rsdt_t *) rsdp->rsdt_address; + + end = (char *)rsdt + rsdt->header.length; + printk(BIOS_DEBUG, "RSDT found at %p ends at %p\n", rsdt, end); + + for (i = 0; ((char *)&rsdt->entry[i]) < end; i++) { + fadt = (acpi_fadt_t *)rsdt->entry[i]; + if (strncmp((char *)fadt, "FACP", 4) == 0) + break; + fadt = NULL; + } + + if (fadt == NULL) + return NULL; + + printk(BIOS_DEBUG, "FADT found at %p\n", fadt); + facs = (acpi_facs_t *)fadt->firmware_ctrl; + + if (facs == NULL) { + printk(BIOS_DEBUG, "No FACS found, wake up from S3 not " + "possible.\n"); + return NULL; + } + + printk(BIOS_DEBUG, "FACS found at %p\n", facs); + wake_vec = (void *)facs->firmware_waking_vector; + printk(BIOS_DEBUG, "OS waking vector is %p\n", wake_vec); + + return wake_vec; +} + +#if CONFIG_SMP +extern char *lowmem_backup; +extern char *lowmem_backup_ptr; +extern int lowmem_backup_size; +#endif + +#define WAKEUP_BASE 0x600 + +void (*acpi_do_wakeup)(u32 vector, u32 backup_source, u32 backup_target, + u32 backup_size) asmlinkage = (void *)WAKEUP_BASE; + +extern unsigned char __wakeup; +extern unsigned int __wakeup_size; + +void acpi_jump_to_wakeup(void *vector) +{ + u32 acpi_backup_memory = 0; + + if (HIGH_MEMORY_SAVE && acpi_s3_resume_allowed()) { + acpi_backup_memory = (u32)cbmem_find(CBMEM_ID_RESUME); + + if (!acpi_backup_memory) { + printk(BIOS_WARNING, "ACPI: Backup memory missing. " + "No S3 resume.\n"); + return; + } + } + +#if CONFIG_SMP + // FIXME: This should go into the ACPI backup memory, too. No pork sausages. + /* + * Just restore the SMP trampoline and continue with wakeup on + * assembly level. + */ + memcpy(lowmem_backup_ptr, lowmem_backup, lowmem_backup_size); +#endif + + /* Copy wakeup trampoline in place. */ + memcpy((void *)WAKEUP_BASE, &__wakeup, __wakeup_size); + + timestamp_add_now(TS_ACPI_WAKE_JUMP); + + acpi_do_wakeup((u32)vector, acpi_backup_memory, CONFIG_RAMBASE, + HIGH_MEMORY_SAVE); +} +#endif + +void acpi_save_gnvs(u32 gnvs_address) +{ + u32 *gnvs = cbmem_add(CBMEM_ID_ACPI_GNVS_PTR, sizeof(*gnvs)); + if (gnvs) + *gnvs = gnvs_address; +} diff --git a/src/arch/x86/acpigen.c b/src/arch/x86/acpigen.c new file mode 100644 index 0000000000..3aa823c363 --- /dev/null +++ b/src/arch/x86/acpigen.c @@ -0,0 +1,728 @@ +/* + * This file is part of the coreboot project. + * + * Copyright (C) 2009 Rudolf Marek + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; version 2 of the License. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc. + */ + +/* How much nesting do we support? */ +#define ACPIGEN_LENSTACK_SIZE 10 + +/* + * If you need to change this, change acpigen_write_f and + * acpigen_pop_len + */ + +#define ACPIGEN_MAXLEN 0xfff + +#include +#include +#include +#include + +static char *gencurrent; + +char *len_stack[ACPIGEN_LENSTACK_SIZE]; +int ltop = 0; + +void acpigen_write_len_f(void) +{ + ASSERT(ltop < (ACPIGEN_LENSTACK_SIZE - 1)) + len_stack[ltop++] = gencurrent; + acpigen_emit_byte(0); + acpigen_emit_byte(0); +} + +void acpigen_pop_len(void) +{ + int len; + ASSERT(ltop > 0) + char *p = len_stack[--ltop]; + len = gencurrent - p; + ASSERT(len <= ACPIGEN_MAXLEN) + /* generate store length for 0xfff max */ + p[0] = (0x40 | (len & 0xf)); + p[1] = (len >> 4 & 0xff); + +} + +void acpigen_set_current(char *curr) +{ + gencurrent = curr; +} + +char *acpigen_get_current(void) +{ + return gencurrent; +} + +void acpigen_emit_byte(unsigned char b) +{ + (*gencurrent++) = b; +} + +void acpigen_write_package(int nr_el) +{ + /* package op */ + acpigen_emit_byte(0x12); + acpigen_write_len_f(); + acpigen_emit_byte(nr_el); +} + +void acpigen_write_byte(unsigned int data) +{ + /* byte op */ + acpigen_emit_byte(0xa); + acpigen_emit_byte(data & 0xff); +} + +void acpigen_write_dword(unsigned int data) +{ + /* dword op */ + acpigen_emit_byte(0xc); + acpigen_emit_byte(data & 0xff); + acpigen_emit_byte((data >> 8) & 0xff); + acpigen_emit_byte((data >> 16) & 0xff); + acpigen_emit_byte((data >> 24) & 0xff); +} + +void acpigen_write_qword(uint64_t data) +{ + /* qword op */ + acpigen_emit_byte(0xe); + acpigen_emit_byte(data & 0xff); + acpigen_emit_byte((data >> 8) & 0xff); + acpigen_emit_byte((data >> 16) & 0xff); + acpigen_emit_byte((data >> 24) & 0xff); + acpigen_emit_byte((data >> 32) & 0xff); + acpigen_emit_byte((data >> 40) & 0xff); + acpigen_emit_byte((data >> 48) & 0xff); + acpigen_emit_byte((data >> 56) & 0xff); +} + +void acpigen_write_name_byte(const char *name, uint8_t val) +{ + acpigen_write_name(name); + acpigen_write_byte(val); +} + +void acpigen_write_name_dword(const char *name, uint32_t val) +{ + acpigen_write_name(name); + acpigen_write_dword(val); +} + +void acpigen_write_name_qword(const char *name, uint64_t val) +{ + acpigen_write_name(name); + acpigen_write_qword(val); +} + +void acpigen_emit_stream(const char *data, int size) +{ + int i; + for (i = 0; i < size; i++) { + acpigen_emit_byte(data[i]); + } +} + +/* + * The naming conventions for ACPI namespace names are a bit tricky as + * each element has to be 4 chars wide (»All names are a fixed 32 bits.«) + * and »By convention, when an ASL compiler pads a name shorter than 4 + * characters, it is done so with trailing underscores (‘_’).«. + * + * Check sections 5.3, 18.2.2 and 18.4 of ACPI spec 3.0 for details. + */ + +static void acpigen_emit_simple_namestring(const char *name) { + int i; + char ud[] = "____"; + for (i = 0; i < 4; i++) { + if ((name[i] == '\0') || (name[i] == '.')) { + acpigen_emit_stream(ud, 4 - i); + break; + } else { + acpigen_emit_byte(name[i]); + } + } +} + +static void acpigen_emit_double_namestring(const char *name, int dotpos) { + /* mark dual name prefix */ + acpigen_emit_byte(0x2e); + acpigen_emit_simple_namestring(name); + acpigen_emit_simple_namestring(&name[dotpos + 1]); +} + +static void acpigen_emit_multi_namestring(const char *name) { + int count = 0; + unsigned char *pathlen; + /* mark multi name prefix */ + acpigen_emit_byte(0x2f); + acpigen_emit_byte(0x0); + pathlen = ((unsigned char *) acpigen_get_current()) - 1; + + while (name[0] != '\0') { + acpigen_emit_simple_namestring(name); + /* find end or next entity */ + while ((name[0] != '.') && (name[0] != '\0')) + name++; + /* forward to next */ + if (name[0] == '.') + name++; + count++; + } + + pathlen[0] = count; +} + + +void acpigen_emit_namestring(const char *namepath) { + int dotcount = 0, i; + int dotpos = 0; + + /* We can start with a '\'. */ + if (namepath[0] == '\\') { + acpigen_emit_byte('\\'); + namepath++; + } + + /* And there can be any number of '^' */ + while (namepath[0] == '^') { + acpigen_emit_byte('^'); + namepath++; + } + + /* If we have only \\ or only ^...^. Then we need to put a null + name (0x00). */ + if(namepath[0] == '\0') { + acpigen_emit_byte(0x00); + return; + } + + i = 0; + while (namepath[i] != '\0') { + if (namepath[i] == '.') { + dotcount++; + dotpos = i; + } + i++; + } + + if (dotcount == 0) { + acpigen_emit_simple_namestring(namepath); + } else if (dotcount == 1) { + acpigen_emit_double_namestring(namepath, dotpos); + } else { + acpigen_emit_multi_namestring(namepath); + } +} + +void acpigen_write_name(const char *name) +{ + /* name op */ + acpigen_emit_byte(0x8); + acpigen_emit_namestring(name); +} + +void acpigen_write_scope(const char *name) +{ + /* scope op */ + acpigen_emit_byte(0x10); + acpigen_write_len_f(); + acpigen_emit_namestring(name); +} + +void acpigen_write_processor(u8 cpuindex, u32 pblock_addr, u8 pblock_len) +{ +/* + Processor (\_PR.CPUcpuindex, cpuindex, pblock_addr, pblock_len) + { +*/ + char pscope[16]; + /* processor op */ + acpigen_emit_byte(0x5b); + acpigen_emit_byte(0x83); + acpigen_write_len_f(); + + snprintf(pscope, sizeof (pscope), + "\\_PR.CP%02d", (unsigned int) cpuindex); + acpigen_emit_namestring(pscope); + acpigen_emit_byte(cpuindex); + acpigen_emit_byte(pblock_addr & 0xff); + acpigen_emit_byte((pblock_addr >> 8) & 0xff); + acpigen_emit_byte((pblock_addr >> 16) & 0xff); + acpigen_emit_byte((pblock_addr >> 24) & 0xff); + acpigen_emit_byte(pblock_len); +} + +void acpigen_write_empty_PCT(void) +{ +/* + Name (_PCT, Package (0x02) + { + ResourceTemplate () + { + Register (FFixedHW, + 0x00, // Bit Width + 0x00, // Bit Offset + 0x0000000000000000, // Address + ,) + }, + + ResourceTemplate () + { + Register (FFixedHW, + 0x00, // Bit Width + 0x00, // Bit Offset + 0x0000000000000000, // Address + ,) + } + }) +*/ + static char stream[] = { + 0x08, 0x5F, 0x50, 0x43, 0x54, 0x12, 0x2C, /* 00000030 "0._PCT.," */ + 0x02, 0x11, 0x14, 0x0A, 0x11, 0x82, 0x0C, 0x00, /* 00000038 "........" */ + 0x7F, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 00000040 "........" */ + 0x00, 0x00, 0x00, 0x00, 0x79, 0x00, 0x11, 0x14, /* 00000048 "....y..." */ + 0x0A, 0x11, 0x82, 0x0C, 0x00, 0x7F, 0x00, 0x00, /* 00000050 "........" */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 00000058 "........" */ + 0x00, 0x79, 0x00 + }; + acpigen_emit_stream(stream, ARRAY_SIZE(stream)); +} + +void acpigen_write_empty_PTC(void) +{ +/* + Name (_PTC, Package (0x02) + { + ResourceTemplate () + { + Register (FFixedHW, + 0x00, // Bit Width + 0x00, // Bit Offset + 0x0000000000000000, // Address + ,) + }, + + ResourceTemplate () + { + Register (FFixedHW, + 0x00, // Bit Width + 0x00, // Bit Offset + 0x0000000000000000, // Address + ,) + } + }) +*/ + acpi_addr_t addr = { + .space_id = ACPI_ADDRESS_SPACE_FIXED, + .bit_width = 0, + .bit_offset = 0, + { + .resv = 0 + }, + .addrl = 0, + .addrh = 0, + }; + + acpigen_write_name("_PTC"); + acpigen_write_package(2); + + /* ControlRegister */ + acpigen_write_resourcetemplate_header(); + acpigen_write_register(&addr); + acpigen_write_resourcetemplate_footer(); + + /* StatusRegister */ + acpigen_write_resourcetemplate_header(); + acpigen_write_register(&addr); + acpigen_write_resourcetemplate_footer(); + + acpigen_pop_len(); +} + +void acpigen_write_method(const char *name, int nargs) +{ + /* method op */ + acpigen_emit_byte(0x14); + acpigen_write_len_f(); + acpigen_emit_namestring(name); + acpigen_emit_byte(nargs & 7); +} + +void acpigen_write_device(const char *name) +{ + /* method op */ + acpigen_emit_byte(0x5b); + acpigen_emit_byte(0x82); + acpigen_write_len_f(); + acpigen_emit_namestring(name); +} + +/* + * Generates a func with max supported P-states. + */ +void acpigen_write_PPC(u8 nr) +{ +/* + Method (_PPC, 0, NotSerialized) + { + Return (nr) + } +*/ + acpigen_write_method("_PPC", 0); + /* return */ + acpigen_emit_byte(0xa4); + /* arg */ + acpigen_write_byte(nr); + acpigen_pop_len(); +} + +/* + * Generates a func with max supported P-states saved + * in the variable PPCM. + */ +void acpigen_write_PPC_NVS(void) +{ +/* + Method (_PPC, 0, NotSerialized) + { + Return (PPCM) + } +*/ + acpigen_write_method("_PPC", 0); + /* return */ + acpigen_emit_byte(0xa4); + /* arg */ + acpigen_emit_namestring("PPCM"); + acpigen_pop_len(); +} + +void acpigen_write_TPC(const char *gnvs_tpc_limit) +{ +/* + // Sample _TPC method + Method (_TPC, 0, NotSerialized) + { + Return (\TLVL) + } + */ + acpigen_write_method("_TPC", 0); + acpigen_emit_byte(0xa4); /* ReturnOp */ + acpigen_emit_namestring(gnvs_tpc_limit); + acpigen_pop_len(); +} + +void acpigen_write_PSS_package(u32 coreFreq, u32 power, u32 transLat, + u32 busmLat, u32 control, u32 status) +{ + acpigen_write_package(6); + acpigen_write_dword(coreFreq); + acpigen_write_dword(power); + acpigen_write_dword(transLat); + acpigen_write_dword(busmLat); + acpigen_write_dword(control); + acpigen_write_dword(status); + acpigen_pop_len(); + + printk(BIOS_DEBUG, "PSS: %uMHz power %u control 0x%x status 0x%x\n", + coreFreq, power, control, status); +} + +void acpigen_write_PSD_package(u32 domain, u32 numprocs, PSD_coord coordtype) +{ + acpigen_write_name("_PSD"); + acpigen_write_package(1); + acpigen_write_package(5); + acpigen_write_byte(5); // 5 values + acpigen_write_byte(0); // revision 0 + acpigen_write_dword(domain); + acpigen_write_dword(coordtype); + acpigen_write_dword(numprocs); + acpigen_pop_len(); + acpigen_pop_len(); +} + +void acpigen_write_CST_package_entry(acpi_cstate_t *cstate) +{ + acpigen_write_package(4); + acpigen_write_resourcetemplate_header(); + acpigen_write_register(&cstate->resource); + acpigen_write_resourcetemplate_footer(); + acpigen_write_dword(cstate->ctype); + acpigen_write_dword(cstate->latency); + acpigen_write_dword(cstate->power); + acpigen_pop_len(); +} + +void acpigen_write_CST_package(acpi_cstate_t *cstate, int nentries) +{ + int i; + acpigen_write_name("_CST"); + acpigen_write_package(nentries+1); + acpigen_write_dword(nentries); + + for (i = 0; i < nentries; i++) + acpigen_write_CST_package_entry(cstate + i); + + acpigen_pop_len(); +} + +void acpigen_write_TSS_package(int entries, acpi_tstate_t *tstate_list) +{ +/* + Sample _TSS package with 100% and 50% duty cycles + Name (_TSS, Package (0x02) + { + Package(){100, 1000, 0, 0x00, 0) + Package(){50, 520, 0, 0x18, 0) + }) + */ + int i; + acpi_tstate_t *tstate = tstate_list; + + acpigen_write_name("_TSS"); + acpigen_write_package(entries); + + for (i = 0; i < entries; i++) { + acpigen_write_package(5); + acpigen_write_dword(tstate->percent); + acpigen_write_dword(tstate->power); + acpigen_write_dword(tstate->latency); + acpigen_write_dword(tstate->control); + acpigen_write_dword(tstate->status); + acpigen_pop_len(); + tstate++; + } + + acpigen_pop_len(); +} + +void acpigen_write_TSD_package(u32 domain, u32 numprocs, PSD_coord coordtype) +{ + acpigen_write_name("_TSD"); + acpigen_write_package(1); + acpigen_write_package(5); + acpigen_write_byte(5); // 5 values + acpigen_write_byte(0); // revision 0 + acpigen_write_dword(domain); + acpigen_write_dword(coordtype); + acpigen_write_dword(numprocs); + acpigen_pop_len(); + acpigen_pop_len(); +} + + + +void acpigen_write_mem32fixed(int readwrite, u32 base, u32 size) +{ + /* + * acpi 4.0 section 6.4.3.4: 32-Bit Fixed Memory Range Descriptor + * Byte 0: + * Bit7 : 1 => big item + * Bit6-0: 0000110 (0x6) => 32-bit fixed memory + */ + acpigen_emit_byte(0x86); + /* Byte 1+2: length (0x0009) */ + acpigen_emit_byte(0x09); + acpigen_emit_byte(0x00); + /* bit1-7 are ignored */ + acpigen_emit_byte(readwrite ? 0x01 : 0x00); + acpigen_emit_byte(base & 0xff); + acpigen_emit_byte((base >> 8) & 0xff); + acpigen_emit_byte((base >> 16) & 0xff); + acpigen_emit_byte((base >> 24) & 0xff); + acpigen_emit_byte(size & 0xff); + acpigen_emit_byte((size >> 8) & 0xff); + acpigen_emit_byte((size >> 16) & 0xff); + acpigen_emit_byte((size >> 24) & 0xff); +} + +void acpigen_write_register(acpi_addr_t *addr) +{ + acpigen_emit_byte(0x82); /* Register Descriptor */ + acpigen_emit_byte(0x0c); /* Register Length 7:0 */ + acpigen_emit_byte(0x00); /* Register Length 15:8 */ + acpigen_emit_byte(addr->space_id); /* Address Space ID */ + acpigen_emit_byte(addr->bit_width); /* Register Bit Width */ + acpigen_emit_byte(addr->bit_offset); /* Register Bit Offset */ + acpigen_emit_byte(addr->resv); /* Register Access Size */ + acpigen_emit_byte(addr->addrl & 0xff); /* Register Address Low */ + acpigen_emit_byte((addr->addrl >> 8) & 0xff); + acpigen_emit_byte((addr->addrl >> 16) & 0xff); + acpigen_emit_byte((addr->addrl >> 24) & 0xff); + acpigen_emit_byte(addr->addrh & 0xff); /* Register Address High */ + acpigen_emit_byte((addr->addrh >> 8) & 0xff); + acpigen_emit_byte((addr->addrh >> 16) & 0xff); + acpigen_emit_byte((addr->addrh >> 24) & 0xff); +} + +void acpigen_write_irq(u16 mask) +{ + /* + * acpi 3.0b section 6.4.2.1: IRQ Descriptor + * Byte 0: + * Bit7 : 0 => small item + * Bit6-3: 0100 (0x4) => IRQ port descriptor + * Bit2-0: 010 (0x2) => 2 Bytes long + */ + acpigen_emit_byte(0x22); + acpigen_emit_byte(mask & 0xff); + acpigen_emit_byte((mask >> 8) & 0xff); +} + +void acpigen_write_io16(u16 min, u16 max, u8 align, u8 len, u8 decode16) +{ + /* + * acpi 4.0 section 6.4.2.6: I/O Port Descriptor + * Byte 0: + * Bit7 : 0 => small item + * Bit6-3: 1000 (0x8) => I/O port descriptor + * Bit2-0: 111 (0x7) => 7 Bytes long + */ + acpigen_emit_byte(0x47); + /* Does the device decode all 16 or just 10 bits? */ + /* bit1-7 are ignored */ + acpigen_emit_byte(decode16 ? 0x01 : 0x00); + /* minimum base address the device may be configured for */ + acpigen_emit_byte(min & 0xff); + acpigen_emit_byte((min >> 8) & 0xff); + /* maximum base address the device may be configured for */ + acpigen_emit_byte(max & 0xff); + acpigen_emit_byte((max >> 8) & 0xff); + /* alignment for min base */ + acpigen_emit_byte(align & 0xff); + acpigen_emit_byte(len & 0xff); +} + +void acpigen_write_resourcetemplate_header(void) +{ + /* + * A ResourceTemplate() is a Buffer() with a + * (Byte|Word|DWord) containing the length, followed by one or more + * resource items, terminated by the end tag. + * (small item 0xf, len 1) + */ + acpigen_emit_byte(0x11); /* Buffer opcode */ + acpigen_write_len_f(); + acpigen_emit_byte(0x0b); /* Word opcode */ + len_stack[ltop++] = acpigen_get_current(); + acpigen_emit_byte(0x00); + acpigen_emit_byte(0x00); +} + +void acpigen_write_resourcetemplate_footer(void) +{ + char *p = len_stack[--ltop]; + int len; + /* + * end tag (acpi 4.0 Section 6.4.2.8) + * 0x79 + * 0x00 is treated as a good checksum according to the spec + * and is what iasl generates. + */ + acpigen_emit_byte(0x79); + acpigen_emit_byte(0x00); + + len = gencurrent - p; + + /* patch len word */ + p[0] = len & 0xff; + p[1] = (len >> 8) & 0xff; + /* patch len field */ + acpigen_pop_len(); +} + +static void acpigen_add_mainboard_rsvd_mem32(void *gp, struct device *dev, + struct resource *res) +{ + acpigen_write_mem32fixed(0, res->base, res->size); +} + +static void acpigen_add_mainboard_rsvd_io(void *gp, struct device *dev, + struct resource *res) +{ + resource_t base = res->base; + resource_t size = res->size; + while (size > 0) { + resource_t sz = size > 255 ? 255 : size; + acpigen_write_io16(base, base, 0, sz, 1); + size -= sz; + base += sz; + } +} + +void acpigen_write_mainboard_resource_template(void) +{ + acpigen_write_resourcetemplate_header(); + + /* Add reserved memory ranges. */ + search_global_resources( + IORESOURCE_MEM | IORESOURCE_RESERVE, + IORESOURCE_MEM | IORESOURCE_RESERVE, + acpigen_add_mainboard_rsvd_mem32, 0); + + /* Add reserved io ranges. */ + search_global_resources( + IORESOURCE_IO | IORESOURCE_RESERVE, + IORESOURCE_IO | IORESOURCE_RESERVE, + acpigen_add_mainboard_rsvd_io, 0); + + acpigen_write_resourcetemplate_footer(); +} + +void acpigen_write_mainboard_resources(const char *scope, const char *name) +{ + acpigen_write_scope(scope); + acpigen_write_name(name); + acpigen_write_mainboard_resource_template(); + acpigen_pop_len(); +} + +static int hex2bin(const char c) +{ + if (c >= 'A' && c <= 'F') + return c - 'A' + 10; + if (c >= 'a' && c <= 'f') + return c - 'a' + 10; + return c - '0'; +} + +void acpigen_emit_eisaid(const char *eisaid) +{ + u32 compact = 0; + + /* Clamping individual values would be better but + there is a disagreement over what is a valid + EISA id, so accept anything and don't clamp, + parent code should create a valid EISAid. + */ + compact |= (eisaid[0] - 'A' + 1) << 26; + compact |= (eisaid[1] - 'A' + 1) << 21; + compact |= (eisaid[2] - 'A' + 1) << 16; + compact |= hex2bin(eisaid[3]) << 12; + compact |= hex2bin(eisaid[4]) << 8; + compact |= hex2bin(eisaid[5]) << 4; + compact |= hex2bin(eisaid[6]); + + acpigen_emit_byte(0xc); + acpigen_emit_byte((compact >> 24) & 0xff); + acpigen_emit_byte((compact >> 16) & 0xff); + acpigen_emit_byte((compact >> 8) & 0xff); + acpigen_emit_byte(compact & 0xff); +} diff --git a/src/arch/x86/boot.c b/src/arch/x86/boot.c new file mode 100644 index 0000000000..7eb87fbef6 --- /dev/null +++ b/src/arch/x86/boot.c @@ -0,0 +1,210 @@ +#include +#include +#include +#include +#include +#include + +/* When the ramstage is relocatable the elf loading ensures an elf image cannot + * be loaded over the ramstage code. */ +static void jmp_payload_no_bounce_buffer(void *entry) +{ + /* Jump to kernel */ + __asm__ __volatile__( + " cld \n\t" + /* Now jump to the loaded image */ + " call *%0\n\t" + + /* The loaded image returned? */ + " cli \n\t" + " cld \n\t" + + :: + "r" (entry) + ); +} + +static void jmp_payload(void *entry, unsigned long buffer, unsigned long size) +{ + unsigned long lb_start, lb_size; + + lb_start = (unsigned long)&_program; + lb_size = _program_size; + + printk(BIOS_SPEW, "entry = 0x%08lx\n", (unsigned long)entry); + printk(BIOS_SPEW, "lb_start = 0x%08lx\n", lb_start); + printk(BIOS_SPEW, "lb_size = 0x%08lx\n", lb_size); + printk(BIOS_SPEW, "buffer = 0x%08lx\n", buffer); + + /* Jump to kernel */ + __asm__ __volatile__( + " cld \n\t" +#ifdef __x86_64__ + /* switch back to 32-bit mode */ + " push %4\n\t" + " push %3\n\t" + " push %2\n\t" + " push %1\n\t" + " push %0\n\t" + + ".intel_syntax noprefix\n\t" + /* use iret to switch to 32-bit code segment */ + " xor rax,rax\n\t" + " mov ax, ss\n\t" + " push rax\n\t" + " mov rax, rsp\n\t" + " add rax, 8\n\t" + " push rax\n\t" + " pushfq\n\t" + " push 0x10\n\t" + " lea rax,[rip+3]\n\t" + " push rax\n\t" + " iretq\n\t" + ".code32\n\t" + /* disable paging */ + " mov eax, cr0\n\t" + " btc eax, 31\n\t" + " mov cr0, eax\n\t" + /* disable long mode */ + " mov ecx, 0xC0000080\n\t" + " rdmsr\n\t" + " btc eax, 8\n\t" + " wrmsr\n\t" + + " pop eax\n\t" + " add esp, 4\n\t" + " pop ebx\n\t" + " add esp, 4\n\t" + " pop ecx\n\t" + + " add esp, 4\n\t" + " pop edx\n\t" + " add esp, 4\n\t" + " pop esi\n\t" + " add esp, 4\n\t" + + ".att_syntax prefix\n\t" +#endif + + /* Save the callee save registers... */ + " pushl %%esi\n\t" + " pushl %%edi\n\t" + " pushl %%ebx\n\t" + /* Save the parameters I was passed */ +#ifdef __x86_64__ + " pushl $0\n\t" /* 20 adjust */ + " pushl %%eax\n\t" /* 16 lb_start */ + " pushl %%ebx\n\t" /* 12 buffer */ + " pushl %%ecx\n\t" /* 8 lb_size */ + " pushl %%edx\n\t" /* 4 entry */ + " pushl %%esi\n\t" /* 0 elf_boot_notes */ +#else + " pushl $0\n\t" /* 20 adjust */ + " pushl %0\n\t" /* 16 lb_start */ + " pushl %1\n\t" /* 12 buffer */ + " pushl %2\n\t" /* 8 lb_size */ + " pushl %3\n\t" /* 4 entry */ + " pushl %4\n\t" /* 0 elf_boot_notes */ + +#endif + /* Compute the adjustment */ + " xorl %%eax, %%eax\n\t" + " subl 16(%%esp), %%eax\n\t" + " addl 12(%%esp), %%eax\n\t" + " addl 8(%%esp), %%eax\n\t" + " movl %%eax, 20(%%esp)\n\t" + /* Place a copy of coreboot in its new location */ + /* Move ``longs'' the coreboot size is 4 byte aligned */ + " movl 12(%%esp), %%edi\n\t" + " addl 8(%%esp), %%edi\n\t" + " movl 16(%%esp), %%esi\n\t" + " movl 8(%%esp), %%ecx\n\n" + " shrl $2, %%ecx\n\t" + " rep movsl\n\t" + + /* Adjust the stack pointer to point into the new coreboot image */ + " addl 20(%%esp), %%esp\n\t" + /* Adjust the instruction pointer to point into the new coreboot image */ + " movl $1f, %%eax\n\t" + " addl 20(%%esp), %%eax\n\t" + " jmp *%%eax\n\t" + "1: \n\t" + + /* Copy the coreboot bounce buffer over coreboot */ + /* Move ``longs'' the coreboot size is 4 byte aligned */ + " movl 16(%%esp), %%edi\n\t" + " movl 12(%%esp), %%esi\n\t" + " movl 8(%%esp), %%ecx\n\t" + " shrl $2, %%ecx\n\t" + " rep movsl\n\t" + + /* Now jump to the loaded image */ + " movl %5, %%eax\n\t" + " movl 0(%%esp), %%ebx\n\t" + " call *4(%%esp)\n\t" + + /* The loaded image returned? */ + " cli \n\t" + " cld \n\t" + + /* Copy the saved copy of coreboot where coreboot runs */ + /* Move ``longs'' the coreboot size is 4 byte aligned */ + " movl 16(%%esp), %%edi\n\t" + " movl 12(%%esp), %%esi\n\t" + " addl 8(%%esp), %%esi\n\t" + " movl 8(%%esp), %%ecx\n\t" + " shrl $2, %%ecx\n\t" + " rep movsl\n\t" + + /* Adjust the stack pointer to point into the old coreboot image */ + " subl 20(%%esp), %%esp\n\t" + + /* Adjust the instruction pointer to point into the old coreboot image */ + " movl $1f, %%eax\n\t" + " subl 20(%%esp), %%eax\n\t" + " jmp *%%eax\n\t" + "1: \n\t" + + /* Drop the parameters I was passed */ + " addl $24, %%esp\n\t" + + /* Restore the callee save registers */ + " popl %%ebx\n\t" + " popl %%edi\n\t" + " popl %%esi\n\t" +#ifdef __x86_64__ + ".code64\n\t" +#endif + :: + "ri" (lb_start), "ri" (buffer), "ri" (lb_size), + "ri" (entry), + "ri"(0), "ri" (0) + ); +} + +static void try_payload(struct prog *prog) +{ + if (prog_type(prog) == ASSET_PAYLOAD) { + if (IS_ENABLED(CONFIG_RELOCATABLE_RAMSTAGE)) + jmp_payload_no_bounce_buffer(prog_entry(prog)); + else + jmp_payload(prog_entry(prog), + (uintptr_t)prog_start(prog), + prog_size(prog)); + } +} + +void arch_prog_run(struct prog *prog) +{ + if (ENV_RAMSTAGE) + try_payload(prog); + __asm__ volatile ( +#ifdef __x86_64__ + "jmp *%%rdi\n" +#else + "jmp *%%edi\n" +#endif + + :: "D"(prog_entry(prog)) + ); +} diff --git a/src/arch/x86/boot/Makefile.inc b/src/arch/x86/boot/Makefile.inc deleted file mode 100644 index 10a1efd242..0000000000 --- a/src/arch/x86/boot/Makefile.inc +++ /dev/null @@ -1,22 +0,0 @@ - -ifeq ($(CONFIG_ARCH_ROMSTAGE_X86_32)$(CONFIG_ARCH_ROMSTAGE_X86_64),y) - -romstage-y += cbmem.c -romstage-y += boot.c - -endif # CONFIG_ARCH_ROMSTAGE_X86_32 / CONFIG_ARCH_ROMSTAGE_X86_64 - -ifeq ($(CONFIG_ARCH_RAMSTAGE_X86_32)$(CONFIG_ARCH_RAMSTAGE_X86_64),y) - -ramstage-y += boot.c -ramstage-y += gdt.c -ramstage-y += tables.c -ramstage-y += cbmem.c -ramstage-$(CONFIG_GENERATE_MP_TABLE) += mpspec.c -ramstage-$(CONFIG_GENERATE_PIRQ_TABLE) += pirq_routing.c -ramstage-$(CONFIG_HAVE_ACPI_TABLES) += acpi.c -ramstage-$(CONFIG_GENERATE_SMBIOS_TABLES) += smbios.c -ramstage-$(CONFIG_HAVE_ACPI_TABLES) += acpigen.c -ramstage-$(CONFIG_HAVE_ACPI_RESUME) += wakeup.S - -endif # CONFIG_ARCH_RAMSTAGE_X86_32 / CONFIG_ARCH_RAMSTAGE_X86_64 diff --git a/src/arch/x86/boot/acpi.c b/src/arch/x86/boot/acpi.c deleted file mode 100644 index 134e43782e..0000000000 --- a/src/arch/x86/boot/acpi.c +++ /dev/null @@ -1,1137 +0,0 @@ -/* - * This file is part of the coreboot project. - * - * coreboot ACPI Table support - * written by Stefan Reinauer - * - * Copyright (C) 2004 SUSE LINUX AG - * Copyright (C) 2005-2009 coresystems GmbH - * - * ACPI FADT, FACS, and DSDT table support added by - * Nick Barker , and those portions - * Copyright (C) 2004 Nick Barker - * - * Copyright (C) 2005 ADVANCED MICRO DEVICES, INC. All Rights Reserved. - * 2005.9 yhlu add SRAT table generation - */ - -/* - * Each system port implementing ACPI has to provide two functions: - * - * write_acpi_tables() - * acpi_dump_apics() - * - * See Kontron 986LCD-M port for a good example of an ACPI implementation - * in coreboot. - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -/* FIXME: Kconfig doesn't support overridable defaults :-( */ -#ifndef CONFIG_HPET_MIN_TICKS -#define CONFIG_HPET_MIN_TICKS 0x1000 -#endif - -u8 acpi_checksum(u8 *table, u32 length) -{ - u8 ret = 0; - while (length--) { - ret += *table; - table++; - } - return -ret; -} - -/** - * Add an ACPI table to the RSDT (and XSDT) structure, recalculate length - * and checksum. - */ -void acpi_add_table(acpi_rsdp_t *rsdp, void *table) -{ - int i, entries_num; - acpi_rsdt_t *rsdt; - acpi_xsdt_t *xsdt = NULL; - - /* The RSDT is mandatory... */ - rsdt = (acpi_rsdt_t *)(uintptr_t)rsdp->rsdt_address; - - /* ...while the XSDT is not. */ - if (rsdp->xsdt_address) - xsdt = (acpi_xsdt_t *)((uintptr_t)rsdp->xsdt_address); - - /* This should always be MAX_ACPI_TABLES. */ - entries_num = ARRAY_SIZE(rsdt->entry); - - for (i = 0; i < entries_num; i++) { - if (rsdt->entry[i] == 0) - break; - } - - if (i >= entries_num) { - printk(BIOS_ERR, "ACPI: Error: Could not add ACPI table, " - "too many tables.\n"); - return; - } - - /* Add table to the RSDT. */ - rsdt->entry[i] = (uintptr_t)table; - - /* Fix RSDT length or the kernel will assume invalid entries. */ - rsdt->header.length = sizeof(acpi_header_t) + (sizeof(u32) * (i + 1)); - - /* Re-calculate checksum. */ - rsdt->header.checksum = 0; /* Hope this won't get optimized away */ - rsdt->header.checksum = acpi_checksum((u8 *)rsdt, rsdt->header.length); - - /* - * And now the same thing for the XSDT. We use the same index as for - * now we want the XSDT and RSDT to always be in sync in coreboot. - */ - if (xsdt) { - /* Add table to the XSDT. */ - xsdt->entry[i] = (u64)(uintptr_t)table; - - /* Fix XSDT length. */ - xsdt->header.length = sizeof(acpi_header_t) + - (sizeof(u64) * (i + 1)); - - /* Re-calculate checksum. */ - xsdt->header.checksum = 0; - xsdt->header.checksum = acpi_checksum((u8 *)xsdt, - xsdt->header.length); - } - - printk(BIOS_DEBUG, "ACPI: added table %d/%d, length now %d\n", - i + 1, entries_num, rsdt->header.length); -} - -int acpi_create_mcfg_mmconfig(acpi_mcfg_mmconfig_t *mmconfig, u32 base, - u16 seg_nr, u8 start, u8 end) -{ - memset(mmconfig, 0, sizeof(*mmconfig)); - mmconfig->base_address = base; - mmconfig->base_reserved = 0; - mmconfig->pci_segment_group_number = seg_nr; - mmconfig->start_bus_number = start; - mmconfig->end_bus_number = end; - - return sizeof(acpi_mcfg_mmconfig_t); -} - -int acpi_create_madt_lapic(acpi_madt_lapic_t *lapic, u8 cpu, u8 apic) -{ - lapic->type = 0; /* Local APIC structure */ - lapic->length = sizeof(acpi_madt_lapic_t); - lapic->flags = (1 << 0); /* Processor/LAPIC enabled */ - lapic->processor_id = cpu; - lapic->apic_id = apic; - - return lapic->length; -} - -unsigned long acpi_create_madt_lapics(unsigned long current) -{ - struct device *cpu; - int index = 0; - - for (cpu = all_devices; cpu; cpu = cpu->next) { - if ((cpu->path.type != DEVICE_PATH_APIC) || - (cpu->bus->dev->path.type != DEVICE_PATH_CPU_CLUSTER)) { - continue; - } - if (!cpu->enabled) - continue; - current += acpi_create_madt_lapic((acpi_madt_lapic_t *)current, - index, cpu->path.apic.apic_id); - index++; - } - - return current; -} - -int acpi_create_madt_ioapic(acpi_madt_ioapic_t *ioapic, u8 id, u32 addr, - u32 gsi_base) -{ - ioapic->type = 1; /* I/O APIC structure */ - ioapic->length = sizeof(acpi_madt_ioapic_t); - ioapic->reserved = 0x00; - ioapic->gsi_base = gsi_base; - ioapic->ioapic_id = id; - ioapic->ioapic_addr = addr; - - return ioapic->length; -} - -int acpi_create_madt_irqoverride(acpi_madt_irqoverride_t *irqoverride, - u8 bus, u8 source, u32 gsirq, u16 flags) -{ - irqoverride->type = 2; /* Interrupt source override */ - irqoverride->length = sizeof(acpi_madt_irqoverride_t); - irqoverride->bus = bus; - irqoverride->source = source; - irqoverride->gsirq = gsirq; - irqoverride->flags = flags; - - return irqoverride->length; -} - -int acpi_create_madt_lapic_nmi(acpi_madt_lapic_nmi_t *lapic_nmi, u8 cpu, - u16 flags, u8 lint) -{ - lapic_nmi->type = 4; /* Local APIC NMI structure */ - lapic_nmi->length = sizeof(acpi_madt_lapic_nmi_t); - lapic_nmi->flags = flags; - lapic_nmi->processor_id = cpu; - lapic_nmi->lint = lint; - - return lapic_nmi->length; -} - -void acpi_create_madt(acpi_madt_t *madt) -{ - acpi_header_t *header = &(madt->header); - unsigned long current = (unsigned long)madt + sizeof(acpi_madt_t); - - memset((void *)madt, 0, sizeof(acpi_madt_t)); - - /* Fill out header fields. */ - memcpy(header->signature, "APIC", 4); - memcpy(header->oem_id, OEM_ID, 6); - memcpy(header->oem_table_id, ACPI_TABLE_CREATOR, 8); - memcpy(header->asl_compiler_id, ASLC, 4); - - header->length = sizeof(acpi_madt_t); - header->revision = 1; /* ACPI 1.0/2.0: 1, ACPI 3.0: 2, ACPI 4.0: 3 */ - - madt->lapic_addr = LOCAL_APIC_ADDR; - madt->flags = 0x1; /* PCAT_COMPAT */ - - current = acpi_fill_madt(current); - - /* (Re)calculate length and checksum. */ - header->length = current - (unsigned long)madt; - - header->checksum = acpi_checksum((void *)madt, header->length); -} - -/* MCFG is defined in the PCI Firmware Specification 3.0. */ -void acpi_create_mcfg(acpi_mcfg_t *mcfg) -{ - acpi_header_t *header = &(mcfg->header); - unsigned long current = (unsigned long)mcfg + sizeof(acpi_mcfg_t); - - memset((void *)mcfg, 0, sizeof(acpi_mcfg_t)); - - /* Fill out header fields. */ - memcpy(header->signature, "MCFG", 4); - memcpy(header->oem_id, OEM_ID, 6); - memcpy(header->oem_table_id, ACPI_TABLE_CREATOR, 8); - memcpy(header->asl_compiler_id, ASLC, 4); - - header->length = sizeof(acpi_mcfg_t); - header->revision = 1; - - current = acpi_fill_mcfg(current); - - /* (Re)calculate length and checksum. */ - header->length = current - (unsigned long)mcfg; - header->checksum = acpi_checksum((void *)mcfg, header->length); -} - -static void *get_tcpa_log(u32 *size) -{ - const struct cbmem_entry *ce; - const u32 tcpa_default_log_len = 0x10000; - void *lasa; - ce = cbmem_entry_find(CBMEM_ID_TCPA_LOG); - if (ce) { - lasa = cbmem_entry_start(ce); - *size = cbmem_entry_size(ce); - printk(BIOS_DEBUG, "TCPA log found at %p\n", lasa); - return lasa; - } - lasa = cbmem_add(CBMEM_ID_TCPA_LOG, tcpa_default_log_len); - if (!lasa) { - printk(BIOS_ERR, "TCPA log creation failed\n"); - return NULL; - } - - printk(BIOS_DEBUG, "TCPA log created at %p\n", lasa); - memset (lasa, 0, tcpa_default_log_len); - - *size = tcpa_default_log_len; - return lasa; -} - -static void acpi_create_tcpa(acpi_tcpa_t *tcpa) -{ - acpi_header_t *header = &(tcpa->header); - u32 tcpa_log_len; - void *lasa; - - memset((void *)tcpa, 0, sizeof(acpi_tcpa_t)); - - lasa = get_tcpa_log(&tcpa_log_len); - if (!lasa) { - return; - } - - /* Fill out header fields. */ - memcpy(header->signature, "TCPA", 4); - memcpy(header->oem_id, OEM_ID, 6); - memcpy(header->oem_table_id, ACPI_TABLE_CREATOR, 8); - memcpy(header->asl_compiler_id, ASLC, 4); - - header->length = sizeof(acpi_tcpa_t); - header->revision = 2; - - tcpa->platform_class = 0; - tcpa->laml = tcpa_log_len; - tcpa->lasa = (uintptr_t) lasa; - - /* Calculate checksum. */ - header->checksum = acpi_checksum((void *)tcpa, header->length); -} - -void acpi_create_ssdt_generator(acpi_header_t *ssdt, const char *oem_table_id) -{ - unsigned long current = (unsigned long)ssdt + sizeof(acpi_header_t); - - memset((void *)ssdt, 0, sizeof(acpi_header_t)); - - memcpy(&ssdt->signature, "SSDT", 4); - ssdt->revision = 2; /* ACPI 1.0/2.0: ?, ACPI 3.0/4.0: 2 */ - memcpy(&ssdt->oem_id, OEM_ID, 6); - memcpy(&ssdt->oem_table_id, oem_table_id, 8); - ssdt->oem_revision = 42; - memcpy(&ssdt->asl_compiler_id, ASLC, 4); - ssdt->asl_compiler_revision = 42; - ssdt->length = sizeof(acpi_header_t); - - acpigen_set_current((char *) current); - { - struct device *dev; - for (dev = all_devices; dev; dev = dev->next) - if (dev->ops && dev->ops->acpi_fill_ssdt_generator) { - dev->ops->acpi_fill_ssdt_generator(dev); - } - current = (unsigned long) acpigen_get_current(); - } - - /* (Re)calculate length and checksum. */ - ssdt->length = current - (unsigned long)ssdt; - ssdt->checksum = acpi_checksum((void *)ssdt, ssdt->length); -} - -int acpi_create_srat_lapic(acpi_srat_lapic_t *lapic, u8 node, u8 apic) -{ - memset((void *)lapic, 0, sizeof(acpi_srat_lapic_t)); - - lapic->type = 0; /* Processor local APIC/SAPIC affinity structure */ - lapic->length = sizeof(acpi_srat_lapic_t); - lapic->flags = (1 << 0); /* Enabled (the use of this structure). */ - lapic->proximity_domain_7_0 = node; - /* TODO: proximity_domain_31_8, local SAPIC EID, clock domain. */ - lapic->apic_id = apic; - - return lapic->length; -} - -int acpi_create_srat_mem(acpi_srat_mem_t *mem, u8 node, u32 basek, u32 sizek, - u32 flags) -{ - mem->type = 1; /* Memory affinity structure */ - mem->length = sizeof(acpi_srat_mem_t); - mem->base_address_low = (basek << 10); - mem->base_address_high = (basek >> (32 - 10)); - mem->length_low = (sizek << 10); - mem->length_high = (sizek >> (32 - 10)); - mem->proximity_domain = node; - mem->flags = flags; - - return mem->length; -} - -/* http://www.microsoft.com/whdc/system/sysinternals/sratdwn.mspx */ -void acpi_create_srat(acpi_srat_t *srat, - unsigned long (*acpi_fill_srat)(unsigned long current)) -{ - acpi_header_t *header = &(srat->header); - unsigned long current = (unsigned long)srat + sizeof(acpi_srat_t); - - memset((void *)srat, 0, sizeof(acpi_srat_t)); - - /* Fill out header fields. */ - memcpy(header->signature, "SRAT", 4); - memcpy(header->oem_id, OEM_ID, 6); - memcpy(header->oem_table_id, ACPI_TABLE_CREATOR, 8); - memcpy(header->asl_compiler_id, ASLC, 4); - - header->length = sizeof(acpi_srat_t); - header->revision = 1; /* ACPI 1.0: N/A, 2.0: 1, 3.0: 2, 4.0: 3 */ - - srat->resv = 1; /* Spec: Reserved to 1 for backwards compatibility. */ - - current = acpi_fill_srat(current); - - /* (Re)calculate length and checksum. */ - header->length = current - (unsigned long)srat; - header->checksum = acpi_checksum((void *)srat, header->length); -} - -void acpi_create_dmar(acpi_dmar_t *dmar, - unsigned long (*acpi_fill_dmar) (unsigned long)) -{ - acpi_header_t *header = &(dmar->header); - unsigned long current = (unsigned long)dmar + sizeof(acpi_dmar_t); - - memset((void *)dmar, 0, sizeof(acpi_dmar_t)); - - /* Fill out header fields. */ - memcpy(header->signature, "DMAR", 4); - memcpy(header->oem_id, OEM_ID, 6); - memcpy(header->oem_table_id, ACPI_TABLE_CREATOR, 8); - memcpy(header->asl_compiler_id, ASLC, 4); - - header->length = sizeof(acpi_dmar_t); - header->revision = 1; - - dmar->host_address_width = 40 - 1; /* FIXME: == MTRR size? */ - dmar->flags = 0; - - current = acpi_fill_dmar(current); - - /* (Re)calculate length and checksum. */ - header->length = current - (unsigned long)dmar; - header->checksum = acpi_checksum((void *)dmar, header->length); -} - -unsigned long acpi_create_dmar_drhd(unsigned long current, u8 flags, - u16 segment, u32 bar) -{ - dmar_entry_t *drhd = (dmar_entry_t *)current; - memset(drhd, 0, sizeof(*drhd)); - drhd->type = DMAR_DRHD; - drhd->length = sizeof(*drhd); /* will be fixed up later */ - drhd->flags = flags; - drhd->segment = segment; - drhd->bar = bar; - - return drhd->length; -} - -void acpi_dmar_drhd_fixup(unsigned long base, unsigned long current) -{ - dmar_entry_t *drhd = (dmar_entry_t *)base; - drhd->length = current - base; -} - -unsigned long acpi_create_dmar_drhd_ds_pci(unsigned long current, u8 segment, - u8 dev, u8 fn) -{ - dev_scope_t *ds = (dev_scope_t *)current; - memset(ds, 0, sizeof(*ds)); - ds->type = SCOPE_PCI_ENDPOINT; - ds->length = sizeof(*ds) + 2; /* we don't support longer paths yet */ - ds->start_bus = segment; - ds->path[0].dev = dev; - ds->path[0].fn = fn; - - return ds->length; -} - -/* http://h21007.www2.hp.com/portal/download/files/unprot/Itanium/slit.pdf */ -void acpi_create_slit(acpi_slit_t *slit, - unsigned long (*acpi_fill_slit)(unsigned long current)) -{ - acpi_header_t *header = &(slit->header); - unsigned long current = (unsigned long)slit + sizeof(acpi_slit_t); - - memset((void *)slit, 0, sizeof(acpi_slit_t)); - - /* Fill out header fields. */ - memcpy(header->signature, "SLIT", 4); - memcpy(header->oem_id, OEM_ID, 6); - memcpy(header->oem_table_id, ACPI_TABLE_CREATOR, 8); - memcpy(header->asl_compiler_id, ASLC, 4); - - header->length = sizeof(acpi_slit_t); - header->revision = 1; /* ACPI 1.0: N/A, ACPI 2.0/3.0/4.0: 1 */ - - current = acpi_fill_slit(current); - - /* (Re)calculate length and checksum. */ - header->length = current - (unsigned long)slit; - header->checksum = acpi_checksum((void *)slit, header->length); -} - -/* http://www.intel.com/hardwaredesign/hpetspec_1.pdf */ -void acpi_create_hpet(acpi_hpet_t *hpet) -{ - acpi_header_t *header = &(hpet->header); - acpi_addr_t *addr = &(hpet->addr); - - memset((void *)hpet, 0, sizeof(acpi_hpet_t)); - - /* Fill out header fields. */ - memcpy(header->signature, "HPET", 4); - memcpy(header->oem_id, OEM_ID, 6); - memcpy(header->oem_table_id, ACPI_TABLE_CREATOR, 8); - memcpy(header->asl_compiler_id, ASLC, 4); - - header->length = sizeof(acpi_hpet_t); - header->revision = 1; /* Currently 1. Table added in ACPI 2.0. */ - - /* Fill out HPET address. */ - addr->space_id = 0; /* Memory */ - addr->bit_width = 64; - addr->bit_offset = 0; - addr->addrl = CONFIG_HPET_ADDRESS & 0xffffffff; - addr->addrh = ((unsigned long long)CONFIG_HPET_ADDRESS) >> 32; - - hpet->id = *(unsigned int*)CONFIG_HPET_ADDRESS; - hpet->number = 0; - hpet->min_tick = CONFIG_HPET_MIN_TICKS; - - header->checksum = acpi_checksum((void *)hpet, sizeof(acpi_hpet_t)); -} - -unsigned long acpi_write_hpet(device_t device, unsigned long current, acpi_rsdp_t *rsdp) -{ - acpi_hpet_t *hpet; - - /* - * We explicitly add these tables later on: - */ - printk(BIOS_DEBUG, "ACPI: * HPET\n"); - - hpet = (acpi_hpet_t *) current; - current += sizeof(acpi_hpet_t); - current = ALIGN(current, 16); - acpi_create_hpet(hpet); - acpi_add_table(rsdp, hpet); - - return current; -} - -void acpi_create_facs(acpi_facs_t *facs) -{ - memset((void *)facs, 0, sizeof(acpi_facs_t)); - - memcpy(facs->signature, "FACS", 4); - facs->length = sizeof(acpi_facs_t); - facs->hardware_signature = 0; - facs->firmware_waking_vector = 0; - facs->global_lock = 0; - facs->flags = 0; - facs->x_firmware_waking_vector_l = 0; - facs->x_firmware_waking_vector_h = 0; - facs->version = 1; /* ACPI 1.0: 0, ACPI 2.0/3.0: 1, ACPI 4.0: 2 */ -} - -static void acpi_write_rsdt(acpi_rsdt_t *rsdt, char *oem_id, char *oem_table_id) -{ - acpi_header_t *header = &(rsdt->header); - - /* Fill out header fields. */ - memcpy(header->signature, "RSDT", 4); - memcpy(header->oem_id, oem_id, 6); - memcpy(header->oem_table_id, oem_table_id, 8); - memcpy(header->asl_compiler_id, ASLC, 4); - - header->length = sizeof(acpi_rsdt_t); - header->revision = 1; /* ACPI 1.0/2.0/3.0/4.0: 1 */ - - /* Entries are filled in later, we come with an empty set. */ - - /* Fix checksum. */ - header->checksum = acpi_checksum((void *)rsdt, sizeof(acpi_rsdt_t)); -} - -static void acpi_write_xsdt(acpi_xsdt_t *xsdt, char *oem_id, char *oem_table_id) -{ - acpi_header_t *header = &(xsdt->header); - - /* Fill out header fields. */ - memcpy(header->signature, "XSDT", 4); - memcpy(header->oem_id, oem_id, 6); - memcpy(header->oem_table_id, oem_table_id, 8); - memcpy(header->asl_compiler_id, ASLC, 4); - - header->length = sizeof(acpi_xsdt_t); - header->revision = 1; /* ACPI 1.0: N/A, 2.0/3.0/4.0: 1 */ - - /* Entries are filled in later, we come with an empty set. */ - - /* Fix checksum. */ - header->checksum = acpi_checksum((void *)xsdt, sizeof(acpi_xsdt_t)); -} - -static void acpi_write_rsdp(acpi_rsdp_t *rsdp, acpi_rsdt_t *rsdt, - acpi_xsdt_t *xsdt, char *oem_id) -{ - memset(rsdp, 0, sizeof(acpi_rsdp_t)); - - memcpy(rsdp->signature, RSDP_SIG, 8); - memcpy(rsdp->oem_id, oem_id, 6); - - rsdp->length = sizeof(acpi_rsdp_t); - rsdp->rsdt_address = (uintptr_t)rsdt; - - /* - * Revision: ACPI 1.0: 0, ACPI 2.0/3.0/4.0: 2. - * - * Some OSes expect an XSDT to be present for RSD PTR revisions >= 2. - * If we don't have an ACPI XSDT, force ACPI 1.0 (and thus RSD PTR - * revision 0). - */ - if (xsdt == NULL) { - rsdp->revision = 0; - } else { - rsdp->xsdt_address = (u64)(uintptr_t)xsdt; - rsdp->revision = 2; - } - - /* Calculate checksums. */ - rsdp->checksum = acpi_checksum((void *)rsdp, 20); - rsdp->ext_checksum = acpi_checksum((void *)rsdp, sizeof(acpi_rsdp_t)); -} - -unsigned long acpi_create_hest_error_source(acpi_hest_t *hest, acpi_hest_esd_t *esd, u16 type, void *data, u16 data_len) -{ - acpi_header_t *header = &(hest->header); - acpi_hest_hen_t *hen; - void *pos; - u16 len; - - pos = esd; - memset(pos, 0, sizeof(acpi_hest_esd_t)); - len = 0; - esd->type = type; /* MCE */ - esd->source_id = hest->error_source_count; - esd->flags = 0; /* FIRMWARE_FIRST */ - esd->enabled = 1; - esd->prealloc_erecords = 1; - esd->max_section_per_record = 0x1; - - len += sizeof(acpi_hest_esd_t); - pos = esd + 1; - - switch (type) { - case 0: /* MCE */ - break; - case 1: /* CMC */ - hen = (acpi_hest_hen_t *) (pos); - memset(pos, 0, sizeof(acpi_hest_hen_t)); - hen->type = 3; /* SCI? */ - hen->length = sizeof(acpi_hest_hen_t); - hen->conf_we = 0; /* Configuration Write Enable. */ - hen->poll_interval = 0; - hen->vector = 0; - hen->sw2poll_threshold_val = 0; - hen->sw2poll_threshold_win = 0; - hen->error_threshold_val = 0; - hen->error_threshold_win = 0; - len += sizeof(acpi_hest_hen_t); - pos = hen + 1; - break; - case 2: /* NMI */ - case 6: /* AER Root Port */ - case 7: /* AER Endpoint */ - case 8: /* AER Bridge */ - case 9: /* Generic Hardware Error Source. */ - /* TODO: */ - break; - default: - printk(BIOS_DEBUG, "Invalid type of Error Source."); - break; - } - hest->error_source_count ++; - - memcpy(pos, data, data_len); - len += data_len; - header->length += len; - - return len; -} - -/* ACPI 4.0 */ -void acpi_write_hest(acpi_hest_t *hest, - unsigned long (*acpi_fill_hest)(acpi_hest_t *hest)) -{ - acpi_header_t *header = &(hest->header); - - memset(hest, 0, sizeof(acpi_hest_t)); - - memcpy(header->signature, "HEST", 4); - memcpy(header->oem_id, OEM_ID, 6); - memcpy(header->oem_table_id, ACPI_TABLE_CREATOR, 8); - memcpy(header->asl_compiler_id, ASLC, 4); - header->length += sizeof(acpi_hest_t); - header->revision = 1; - - acpi_fill_hest(hest); - - /* Calculate checksums. */ - header->checksum = acpi_checksum((void *)hest, header->length); -} - -#if IS_ENABLED(CONFIG_COMMON_FADT) -void acpi_create_fadt(acpi_fadt_t *fadt,acpi_facs_t *facs, void *dsdt) -{ - acpi_header_t *header = &(fadt->header); - - memset((void *) fadt, 0, sizeof(acpi_fadt_t)); - memcpy(header->signature, "FACP", 4); - header->length = sizeof(acpi_fadt_t); - header->revision = 4; - memcpy(header->oem_id, OEM_ID, 6); - memcpy(header->oem_table_id, ACPI_TABLE_CREATOR, 8); - memcpy(header->asl_compiler_id, ASLC, 4); - header->asl_compiler_revision = 0; - - fadt->firmware_ctrl = (unsigned long) facs; - fadt->dsdt = (unsigned long) dsdt; - - fadt->x_firmware_ctl_l = (unsigned long)facs; - fadt->x_firmware_ctl_h = 0; - fadt->x_dsdt_l = (unsigned long)dsdt; - fadt->x_dsdt_h = 0; - - if(IS_ENABLED(CONFIG_SYSTEM_TYPE_LAPTOP)) { - fadt->preferred_pm_profile = PM_MOBILE; - } else { - fadt->preferred_pm_profile = PM_DESKTOP; - } - - acpi_fill_fadt(fadt); - - header->checksum = - acpi_checksum((void *) fadt, header->length); -} -#endif - -unsigned long __attribute__ ((weak)) fw_cfg_acpi_tables(unsigned long start) -{ - return 0; -} - -#define ALIGN_CURRENT current = (ALIGN(current, 16)) -unsigned long write_acpi_tables(unsigned long start) -{ - unsigned long current; - acpi_rsdp_t *rsdp; - acpi_rsdt_t *rsdt; - acpi_xsdt_t *xsdt; - acpi_fadt_t *fadt; - acpi_facs_t *facs; - acpi_header_t *slic_file, *slic; - acpi_header_t *ssdt; - acpi_header_t *dsdt_file, *dsdt; - acpi_mcfg_t *mcfg; - acpi_tcpa_t *tcpa; - acpi_madt_t *madt; - struct device *dev; - unsigned long fw; - size_t slic_size, dsdt_size; - char oem_id[6], oem_table_id[8]; - - current = start; - - /* Align ACPI tables to 16byte */ - ALIGN_CURRENT; - - fw = fw_cfg_acpi_tables(current); - if (fw) - return fw; - -#if CONFIG_COMPILE_IN_DSDT - extern char _binary_dsdt_aml_start; - extern char _binary_dsdt_aml_end; - dsdt_file = (acpi_header_t *)&_binary_dsdt_aml_start; - dsdt_size = (size_t)(&_binary_dsdt_aml_end - &_binary_dsdt_aml_start); -#else - dsdt_file = cbfs_boot_map_with_leak( - CONFIG_CBFS_PREFIX "/dsdt.aml", - CBFS_TYPE_RAW, &dsdt_size); -#endif - if (!dsdt_file) { - printk(BIOS_ERR, "No DSDT file, skipping ACPI tables\n"); - return current; - } - - if (dsdt_file->length > dsdt_size - || dsdt_file->length < sizeof (acpi_header_t) - || memcmp(dsdt_file->signature, "DSDT", 4) != 0) { - printk(BIOS_ERR, "Invalid DSDT file, skipping ACPI tables\n"); - return current; - } - - slic_file = cbfs_boot_map_with_leak(CONFIG_CBFS_PREFIX "/slic", - CBFS_TYPE_RAW, &slic_size); - if (slic_file - && (slic_file->length > slic_size - || slic_file->length < sizeof (acpi_header_t) - || memcmp(slic_file->signature, "SLIC", 4) != 0)) { - slic_file = 0; - } - - if (slic_file) { - memcpy(oem_id, slic_file->oem_id, 6); - memcpy(oem_table_id, slic_file->oem_table_id, 8); - } else { - memcpy(oem_id, OEM_ID, 6); - memcpy(oem_table_id, ACPI_TABLE_CREATOR, 8); - } - - printk(BIOS_INFO, "ACPI: Writing ACPI tables at %lx.\n", start); - - /* We need at least an RSDP and an RSDT Table */ - rsdp = (acpi_rsdp_t *) current; - current += sizeof(acpi_rsdp_t); - ALIGN_CURRENT; - rsdt = (acpi_rsdt_t *) current; - current += sizeof(acpi_rsdt_t); - ALIGN_CURRENT; - xsdt = (acpi_xsdt_t *) current; - current += sizeof(acpi_xsdt_t); - ALIGN_CURRENT; - - /* clear all table memory */ - memset((void *) start, 0, current - start); - - acpi_write_rsdp(rsdp, rsdt, xsdt, oem_id); - acpi_write_rsdt(rsdt, oem_id, oem_table_id); - acpi_write_xsdt(xsdt, oem_id, oem_table_id); - - printk(BIOS_DEBUG, "ACPI: * FACS\n"); - facs = (acpi_facs_t *) current; - current += sizeof(acpi_facs_t); - ALIGN_CURRENT; - acpi_create_facs(facs); - - printk(BIOS_DEBUG, "ACPI: * DSDT\n"); - dsdt = (acpi_header_t *) current; - memcpy(dsdt, dsdt_file, sizeof(acpi_header_t)); - if (dsdt->length >= sizeof(acpi_header_t)) { - current += sizeof(acpi_header_t); - - acpigen_set_current((char *) current); - for (dev = all_devices; dev; dev = dev->next) - if (dev->ops && dev->ops->acpi_inject_dsdt_generator) { - dev->ops->acpi_inject_dsdt_generator(dev); - } - current = (unsigned long) acpigen_get_current(); - memcpy((char *)current, - (char *)dsdt_file + sizeof(acpi_header_t), - dsdt->length - sizeof(acpi_header_t)); - current += dsdt->length - sizeof(acpi_header_t); - - /* (Re)calculate length and checksum. */ - dsdt->length = current - (unsigned long)dsdt; - dsdt->checksum = 0; - dsdt->checksum = acpi_checksum((void *)dsdt, dsdt->length); - } - - ALIGN_CURRENT; - - printk(BIOS_DEBUG, "ACPI: * FADT\n"); - fadt = (acpi_fadt_t *) current; - current += sizeof(acpi_fadt_t); - ALIGN_CURRENT; - - acpi_create_fadt(fadt, facs, dsdt); - acpi_add_table(rsdp, fadt); - - if (slic_file) { - printk(BIOS_DEBUG, "ACPI: * SLIC\n"); - slic = (acpi_header_t *)current; - memcpy(slic, slic_file, slic_file->length); - current += slic_file->length; - ALIGN_CURRENT; - acpi_add_table(rsdp, slic); - } - - printk(BIOS_DEBUG, "ACPI: * SSDT\n"); - ssdt = (acpi_header_t *)current; - acpi_create_ssdt_generator(ssdt, ACPI_TABLE_CREATOR); - if (ssdt->length > sizeof(acpi_header_t)) { - current += ssdt->length; - acpi_add_table(rsdp, ssdt); - ALIGN_CURRENT; - } - - printk(BIOS_DEBUG, "ACPI: * MCFG\n"); - mcfg = (acpi_mcfg_t *) current; - acpi_create_mcfg(mcfg); - if (mcfg->header.length > sizeof(acpi_mcfg_t)) { - current += mcfg->header.length; - ALIGN_CURRENT; - acpi_add_table(rsdp, mcfg); - } - - printk(BIOS_DEBUG, "ACPI: * TCPA\n"); - tcpa = (acpi_tcpa_t *) current; - acpi_create_tcpa(tcpa); - if (tcpa->header.length >= sizeof(acpi_tcpa_t)) { - current += tcpa->header.length; - ALIGN_CURRENT; - acpi_add_table(rsdp, tcpa); - } - - printk(BIOS_DEBUG, "ACPI: * MADT\n"); - - madt = (acpi_madt_t *) current; - acpi_create_madt(madt); - if (madt->header.length > sizeof(acpi_madt_t)) { - current+=madt->header.length; - acpi_add_table(rsdp,madt); - } - ALIGN_CURRENT; - - printk(BIOS_DEBUG, "current = %lx\n", current); - - for (dev = all_devices; dev; dev = dev->next) { - if (dev->ops && dev->ops->write_acpi_tables) { - current = dev->ops->write_acpi_tables(dev, current, rsdp); - ALIGN_CURRENT; - } - } - - printk(BIOS_INFO, "ACPI: done.\n"); - return current; -} - -#if CONFIG_HAVE_ACPI_RESUME -void __attribute__((weak)) mainboard_suspend_resume(void) -{ -} - -void acpi_resume(void *wake_vec) -{ -#if CONFIG_HAVE_SMI_HANDLER - u32 *gnvs_address = cbmem_find(CBMEM_ID_ACPI_GNVS_PTR); - - /* Restore GNVS pointer in SMM if found */ - if (gnvs_address && *gnvs_address) { - printk(BIOS_DEBUG, "Restore GNVS pointer to 0x%08x\n", - *gnvs_address); - smm_setup_structures((void *)*gnvs_address, NULL, NULL); - } -#endif - - /* Call mainboard resume handler first, if defined. */ - mainboard_suspend_resume(); - - post_code(POST_OS_RESUME); - acpi_jump_to_wakeup(wake_vec); -} - -/* This is filled with acpi_is_wakeup() call early in ramstage. */ -int acpi_slp_type = -1; - -#if IS_ENABLED(CONFIG_EARLY_CBMEM_INIT) -int acpi_get_sleep_type(void) -{ - struct romstage_handoff *handoff; - - handoff = cbmem_find(CBMEM_ID_ROMSTAGE_INFO); - - if (handoff == NULL) { - printk(BIOS_DEBUG, "Unknown boot method, assuming normal.\n"); - return 0; - } else if (handoff->s3_resume) { - printk(BIOS_DEBUG, "S3 Resume.\n"); - return 3; - } else { - printk(BIOS_DEBUG, "Normal boot.\n"); - return 0; - } -} -#endif - -static void acpi_handoff_wakeup(void) -{ - if (acpi_slp_type < 0) - acpi_slp_type = acpi_get_sleep_type(); -} - -int acpi_is_wakeup(void) -{ - acpi_handoff_wakeup(); - /* Both resume from S2 and resume from S3 restart at CPU reset */ - return (acpi_slp_type == 3 || acpi_slp_type == 2); -} - -int acpi_is_wakeup_s3(void) -{ - acpi_handoff_wakeup(); - return (acpi_slp_type == 3); -} - -void acpi_fail_wakeup(void) -{ - if (acpi_slp_type == 3 || acpi_slp_type == 2) - acpi_slp_type = 0; -} - -void acpi_prepare_resume_backup(void) -{ - if (!acpi_s3_resume_allowed()) - return; - - /* Let's prepare the ACPI S3 Resume area now already, so we can rely on - * it being there during reboot time. We don't need the pointer, nor - * the result right now. If it fails, ACPI resume will be disabled. - */ - - if (HIGH_MEMORY_SAVE) - cbmem_add(CBMEM_ID_RESUME, HIGH_MEMORY_SAVE); -} - -static acpi_rsdp_t *valid_rsdp(acpi_rsdp_t *rsdp) -{ - if (strncmp((char *)rsdp, RSDP_SIG, sizeof(RSDP_SIG) - 1) != 0) - return NULL; - - printk(BIOS_DEBUG, "Looking on %p for valid checksum\n", rsdp); - - if (acpi_checksum((void *)rsdp, 20) != 0) - return NULL; - printk(BIOS_DEBUG, "Checksum 1 passed\n"); - - if ((rsdp->revision > 1) && (acpi_checksum((void *)rsdp, - rsdp->length) != 0)) - return NULL; - printk(BIOS_DEBUG, "Checksum 2 passed all OK\n"); - - return rsdp; -} - -static acpi_rsdp_t *rsdp; - -void *acpi_get_wakeup_rsdp(void) -{ - return rsdp; -} - -void *acpi_find_wakeup_vector(void) -{ - char *p, *end; - acpi_rsdt_t *rsdt; - acpi_facs_t *facs; - acpi_fadt_t *fadt = NULL; - void *wake_vec; - int i; - - rsdp = NULL; - - if (!acpi_is_wakeup()) - return NULL; - - printk(BIOS_DEBUG, "Trying to find the wakeup vector...\n"); - - /* Find RSDP. */ - for (p = (char *)0xe0000; p < (char *)0xfffff; p += 16) { - if ((rsdp = valid_rsdp((acpi_rsdp_t *)p))) - break; - } - - if (rsdp == NULL) - return NULL; - - printk(BIOS_DEBUG, "RSDP found at %p\n", rsdp); - rsdt = (acpi_rsdt_t *) rsdp->rsdt_address; - - end = (char *)rsdt + rsdt->header.length; - printk(BIOS_DEBUG, "RSDT found at %p ends at %p\n", rsdt, end); - - for (i = 0; ((char *)&rsdt->entry[i]) < end; i++) { - fadt = (acpi_fadt_t *)rsdt->entry[i]; - if (strncmp((char *)fadt, "FACP", 4) == 0) - break; - fadt = NULL; - } - - if (fadt == NULL) - return NULL; - - printk(BIOS_DEBUG, "FADT found at %p\n", fadt); - facs = (acpi_facs_t *)fadt->firmware_ctrl; - - if (facs == NULL) { - printk(BIOS_DEBUG, "No FACS found, wake up from S3 not " - "possible.\n"); - return NULL; - } - - printk(BIOS_DEBUG, "FACS found at %p\n", facs); - wake_vec = (void *)facs->firmware_waking_vector; - printk(BIOS_DEBUG, "OS waking vector is %p\n", wake_vec); - - return wake_vec; -} - -#if CONFIG_SMP -extern char *lowmem_backup; -extern char *lowmem_backup_ptr; -extern int lowmem_backup_size; -#endif - -#define WAKEUP_BASE 0x600 - -void (*acpi_do_wakeup)(u32 vector, u32 backup_source, u32 backup_target, - u32 backup_size) asmlinkage = (void *)WAKEUP_BASE; - -extern unsigned char __wakeup; -extern unsigned int __wakeup_size; - -void acpi_jump_to_wakeup(void *vector) -{ - u32 acpi_backup_memory = 0; - - if (HIGH_MEMORY_SAVE && acpi_s3_resume_allowed()) { - acpi_backup_memory = (u32)cbmem_find(CBMEM_ID_RESUME); - - if (!acpi_backup_memory) { - printk(BIOS_WARNING, "ACPI: Backup memory missing. " - "No S3 resume.\n"); - return; - } - } - -#if CONFIG_SMP - // FIXME: This should go into the ACPI backup memory, too. No pork sausages. - /* - * Just restore the SMP trampoline and continue with wakeup on - * assembly level. - */ - memcpy(lowmem_backup_ptr, lowmem_backup, lowmem_backup_size); -#endif - - /* Copy wakeup trampoline in place. */ - memcpy((void *)WAKEUP_BASE, &__wakeup, __wakeup_size); - - timestamp_add_now(TS_ACPI_WAKE_JUMP); - - acpi_do_wakeup((u32)vector, acpi_backup_memory, CONFIG_RAMBASE, - HIGH_MEMORY_SAVE); -} -#endif - -void acpi_save_gnvs(u32 gnvs_address) -{ - u32 *gnvs = cbmem_add(CBMEM_ID_ACPI_GNVS_PTR, sizeof(*gnvs)); - if (gnvs) - *gnvs = gnvs_address; -} diff --git a/src/arch/x86/boot/acpigen.c b/src/arch/x86/boot/acpigen.c deleted file mode 100644 index 3aa823c363..0000000000 --- a/src/arch/x86/boot/acpigen.c +++ /dev/null @@ -1,728 +0,0 @@ -/* - * This file is part of the coreboot project. - * - * Copyright (C) 2009 Rudolf Marek - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; version 2 of the License. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc. - */ - -/* How much nesting do we support? */ -#define ACPIGEN_LENSTACK_SIZE 10 - -/* - * If you need to change this, change acpigen_write_f and - * acpigen_pop_len - */ - -#define ACPIGEN_MAXLEN 0xfff - -#include -#include -#include -#include - -static char *gencurrent; - -char *len_stack[ACPIGEN_LENSTACK_SIZE]; -int ltop = 0; - -void acpigen_write_len_f(void) -{ - ASSERT(ltop < (ACPIGEN_LENSTACK_SIZE - 1)) - len_stack[ltop++] = gencurrent; - acpigen_emit_byte(0); - acpigen_emit_byte(0); -} - -void acpigen_pop_len(void) -{ - int len; - ASSERT(ltop > 0) - char *p = len_stack[--ltop]; - len = gencurrent - p; - ASSERT(len <= ACPIGEN_MAXLEN) - /* generate store length for 0xfff max */ - p[0] = (0x40 | (len & 0xf)); - p[1] = (len >> 4 & 0xff); - -} - -void acpigen_set_current(char *curr) -{ - gencurrent = curr; -} - -char *acpigen_get_current(void) -{ - return gencurrent; -} - -void acpigen_emit_byte(unsigned char b) -{ - (*gencurrent++) = b; -} - -void acpigen_write_package(int nr_el) -{ - /* package op */ - acpigen_emit_byte(0x12); - acpigen_write_len_f(); - acpigen_emit_byte(nr_el); -} - -void acpigen_write_byte(unsigned int data) -{ - /* byte op */ - acpigen_emit_byte(0xa); - acpigen_emit_byte(data & 0xff); -} - -void acpigen_write_dword(unsigned int data) -{ - /* dword op */ - acpigen_emit_byte(0xc); - acpigen_emit_byte(data & 0xff); - acpigen_emit_byte((data >> 8) & 0xff); - acpigen_emit_byte((data >> 16) & 0xff); - acpigen_emit_byte((data >> 24) & 0xff); -} - -void acpigen_write_qword(uint64_t data) -{ - /* qword op */ - acpigen_emit_byte(0xe); - acpigen_emit_byte(data & 0xff); - acpigen_emit_byte((data >> 8) & 0xff); - acpigen_emit_byte((data >> 16) & 0xff); - acpigen_emit_byte((data >> 24) & 0xff); - acpigen_emit_byte((data >> 32) & 0xff); - acpigen_emit_byte((data >> 40) & 0xff); - acpigen_emit_byte((data >> 48) & 0xff); - acpigen_emit_byte((data >> 56) & 0xff); -} - -void acpigen_write_name_byte(const char *name, uint8_t val) -{ - acpigen_write_name(name); - acpigen_write_byte(val); -} - -void acpigen_write_name_dword(const char *name, uint32_t val) -{ - acpigen_write_name(name); - acpigen_write_dword(val); -} - -void acpigen_write_name_qword(const char *name, uint64_t val) -{ - acpigen_write_name(name); - acpigen_write_qword(val); -} - -void acpigen_emit_stream(const char *data, int size) -{ - int i; - for (i = 0; i < size; i++) { - acpigen_emit_byte(data[i]); - } -} - -/* - * The naming conventions for ACPI namespace names are a bit tricky as - * each element has to be 4 chars wide (»All names are a fixed 32 bits.«) - * and »By convention, when an ASL compiler pads a name shorter than 4 - * characters, it is done so with trailing underscores (‘_’).«. - * - * Check sections 5.3, 18.2.2 and 18.4 of ACPI spec 3.0 for details. - */ - -static void acpigen_emit_simple_namestring(const char *name) { - int i; - char ud[] = "____"; - for (i = 0; i < 4; i++) { - if ((name[i] == '\0') || (name[i] == '.')) { - acpigen_emit_stream(ud, 4 - i); - break; - } else { - acpigen_emit_byte(name[i]); - } - } -} - -static void acpigen_emit_double_namestring(const char *name, int dotpos) { - /* mark dual name prefix */ - acpigen_emit_byte(0x2e); - acpigen_emit_simple_namestring(name); - acpigen_emit_simple_namestring(&name[dotpos + 1]); -} - -static void acpigen_emit_multi_namestring(const char *name) { - int count = 0; - unsigned char *pathlen; - /* mark multi name prefix */ - acpigen_emit_byte(0x2f); - acpigen_emit_byte(0x0); - pathlen = ((unsigned char *) acpigen_get_current()) - 1; - - while (name[0] != '\0') { - acpigen_emit_simple_namestring(name); - /* find end or next entity */ - while ((name[0] != '.') && (name[0] != '\0')) - name++; - /* forward to next */ - if (name[0] == '.') - name++; - count++; - } - - pathlen[0] = count; -} - - -void acpigen_emit_namestring(const char *namepath) { - int dotcount = 0, i; - int dotpos = 0; - - /* We can start with a '\'. */ - if (namepath[0] == '\\') { - acpigen_emit_byte('\\'); - namepath++; - } - - /* And there can be any number of '^' */ - while (namepath[0] == '^') { - acpigen_emit_byte('^'); - namepath++; - } - - /* If we have only \\ or only ^...^. Then we need to put a null - name (0x00). */ - if(namepath[0] == '\0') { - acpigen_emit_byte(0x00); - return; - } - - i = 0; - while (namepath[i] != '\0') { - if (namepath[i] == '.') { - dotcount++; - dotpos = i; - } - i++; - } - - if (dotcount == 0) { - acpigen_emit_simple_namestring(namepath); - } else if (dotcount == 1) { - acpigen_emit_double_namestring(namepath, dotpos); - } else { - acpigen_emit_multi_namestring(namepath); - } -} - -void acpigen_write_name(const char *name) -{ - /* name op */ - acpigen_emit_byte(0x8); - acpigen_emit_namestring(name); -} - -void acpigen_write_scope(const char *name) -{ - /* scope op */ - acpigen_emit_byte(0x10); - acpigen_write_len_f(); - acpigen_emit_namestring(name); -} - -void acpigen_write_processor(u8 cpuindex, u32 pblock_addr, u8 pblock_len) -{ -/* - Processor (\_PR.CPUcpuindex, cpuindex, pblock_addr, pblock_len) - { -*/ - char pscope[16]; - /* processor op */ - acpigen_emit_byte(0x5b); - acpigen_emit_byte(0x83); - acpigen_write_len_f(); - - snprintf(pscope, sizeof (pscope), - "\\_PR.CP%02d", (unsigned int) cpuindex); - acpigen_emit_namestring(pscope); - acpigen_emit_byte(cpuindex); - acpigen_emit_byte(pblock_addr & 0xff); - acpigen_emit_byte((pblock_addr >> 8) & 0xff); - acpigen_emit_byte((pblock_addr >> 16) & 0xff); - acpigen_emit_byte((pblock_addr >> 24) & 0xff); - acpigen_emit_byte(pblock_len); -} - -void acpigen_write_empty_PCT(void) -{ -/* - Name (_PCT, Package (0x02) - { - ResourceTemplate () - { - Register (FFixedHW, - 0x00, // Bit Width - 0x00, // Bit Offset - 0x0000000000000000, // Address - ,) - }, - - ResourceTemplate () - { - Register (FFixedHW, - 0x00, // Bit Width - 0x00, // Bit Offset - 0x0000000000000000, // Address - ,) - } - }) -*/ - static char stream[] = { - 0x08, 0x5F, 0x50, 0x43, 0x54, 0x12, 0x2C, /* 00000030 "0._PCT.," */ - 0x02, 0x11, 0x14, 0x0A, 0x11, 0x82, 0x0C, 0x00, /* 00000038 "........" */ - 0x7F, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 00000040 "........" */ - 0x00, 0x00, 0x00, 0x00, 0x79, 0x00, 0x11, 0x14, /* 00000048 "....y..." */ - 0x0A, 0x11, 0x82, 0x0C, 0x00, 0x7F, 0x00, 0x00, /* 00000050 "........" */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 00000058 "........" */ - 0x00, 0x79, 0x00 - }; - acpigen_emit_stream(stream, ARRAY_SIZE(stream)); -} - -void acpigen_write_empty_PTC(void) -{ -/* - Name (_PTC, Package (0x02) - { - ResourceTemplate () - { - Register (FFixedHW, - 0x00, // Bit Width - 0x00, // Bit Offset - 0x0000000000000000, // Address - ,) - }, - - ResourceTemplate () - { - Register (FFixedHW, - 0x00, // Bit Width - 0x00, // Bit Offset - 0x0000000000000000, // Address - ,) - } - }) -*/ - acpi_addr_t addr = { - .space_id = ACPI_ADDRESS_SPACE_FIXED, - .bit_width = 0, - .bit_offset = 0, - { - .resv = 0 - }, - .addrl = 0, - .addrh = 0, - }; - - acpigen_write_name("_PTC"); - acpigen_write_package(2); - - /* ControlRegister */ - acpigen_write_resourcetemplate_header(); - acpigen_write_register(&addr); - acpigen_write_resourcetemplate_footer(); - - /* StatusRegister */ - acpigen_write_resourcetemplate_header(); - acpigen_write_register(&addr); - acpigen_write_resourcetemplate_footer(); - - acpigen_pop_len(); -} - -void acpigen_write_method(const char *name, int nargs) -{ - /* method op */ - acpigen_emit_byte(0x14); - acpigen_write_len_f(); - acpigen_emit_namestring(name); - acpigen_emit_byte(nargs & 7); -} - -void acpigen_write_device(const char *name) -{ - /* method op */ - acpigen_emit_byte(0x5b); - acpigen_emit_byte(0x82); - acpigen_write_len_f(); - acpigen_emit_namestring(name); -} - -/* - * Generates a func with max supported P-states. - */ -void acpigen_write_PPC(u8 nr) -{ -/* - Method (_PPC, 0, NotSerialized) - { - Return (nr) - } -*/ - acpigen_write_method("_PPC", 0); - /* return */ - acpigen_emit_byte(0xa4); - /* arg */ - acpigen_write_byte(nr); - acpigen_pop_len(); -} - -/* - * Generates a func with max supported P-states saved - * in the variable PPCM. - */ -void acpigen_write_PPC_NVS(void) -{ -/* - Method (_PPC, 0, NotSerialized) - { - Return (PPCM) - } -*/ - acpigen_write_method("_PPC", 0); - /* return */ - acpigen_emit_byte(0xa4); - /* arg */ - acpigen_emit_namestring("PPCM"); - acpigen_pop_len(); -} - -void acpigen_write_TPC(const char *gnvs_tpc_limit) -{ -/* - // Sample _TPC method - Method (_TPC, 0, NotSerialized) - { - Return (\TLVL) - } - */ - acpigen_write_method("_TPC", 0); - acpigen_emit_byte(0xa4); /* ReturnOp */ - acpigen_emit_namestring(gnvs_tpc_limit); - acpigen_pop_len(); -} - -void acpigen_write_PSS_package(u32 coreFreq, u32 power, u32 transLat, - u32 busmLat, u32 control, u32 status) -{ - acpigen_write_package(6); - acpigen_write_dword(coreFreq); - acpigen_write_dword(power); - acpigen_write_dword(transLat); - acpigen_write_dword(busmLat); - acpigen_write_dword(control); - acpigen_write_dword(status); - acpigen_pop_len(); - - printk(BIOS_DEBUG, "PSS: %uMHz power %u control 0x%x status 0x%x\n", - coreFreq, power, control, status); -} - -void acpigen_write_PSD_package(u32 domain, u32 numprocs, PSD_coord coordtype) -{ - acpigen_write_name("_PSD"); - acpigen_write_package(1); - acpigen_write_package(5); - acpigen_write_byte(5); // 5 values - acpigen_write_byte(0); // revision 0 - acpigen_write_dword(domain); - acpigen_write_dword(coordtype); - acpigen_write_dword(numprocs); - acpigen_pop_len(); - acpigen_pop_len(); -} - -void acpigen_write_CST_package_entry(acpi_cstate_t *cstate) -{ - acpigen_write_package(4); - acpigen_write_resourcetemplate_header(); - acpigen_write_register(&cstate->resource); - acpigen_write_resourcetemplate_footer(); - acpigen_write_dword(cstate->ctype); - acpigen_write_dword(cstate->latency); - acpigen_write_dword(cstate->power); - acpigen_pop_len(); -} - -void acpigen_write_CST_package(acpi_cstate_t *cstate, int nentries) -{ - int i; - acpigen_write_name("_CST"); - acpigen_write_package(nentries+1); - acpigen_write_dword(nentries); - - for (i = 0; i < nentries; i++) - acpigen_write_CST_package_entry(cstate + i); - - acpigen_pop_len(); -} - -void acpigen_write_TSS_package(int entries, acpi_tstate_t *tstate_list) -{ -/* - Sample _TSS package with 100% and 50% duty cycles - Name (_TSS, Package (0x02) - { - Package(){100, 1000, 0, 0x00, 0) - Package(){50, 520, 0, 0x18, 0) - }) - */ - int i; - acpi_tstate_t *tstate = tstate_list; - - acpigen_write_name("_TSS"); - acpigen_write_package(entries); - - for (i = 0; i < entries; i++) { - acpigen_write_package(5); - acpigen_write_dword(tstate->percent); - acpigen_write_dword(tstate->power); - acpigen_write_dword(tstate->latency); - acpigen_write_dword(tstate->control); - acpigen_write_dword(tstate->status); - acpigen_pop_len(); - tstate++; - } - - acpigen_pop_len(); -} - -void acpigen_write_TSD_package(u32 domain, u32 numprocs, PSD_coord coordtype) -{ - acpigen_write_name("_TSD"); - acpigen_write_package(1); - acpigen_write_package(5); - acpigen_write_byte(5); // 5 values - acpigen_write_byte(0); // revision 0 - acpigen_write_dword(domain); - acpigen_write_dword(coordtype); - acpigen_write_dword(numprocs); - acpigen_pop_len(); - acpigen_pop_len(); -} - - - -void acpigen_write_mem32fixed(int readwrite, u32 base, u32 size) -{ - /* - * acpi 4.0 section 6.4.3.4: 32-Bit Fixed Memory Range Descriptor - * Byte 0: - * Bit7 : 1 => big item - * Bit6-0: 0000110 (0x6) => 32-bit fixed memory - */ - acpigen_emit_byte(0x86); - /* Byte 1+2: length (0x0009) */ - acpigen_emit_byte(0x09); - acpigen_emit_byte(0x00); - /* bit1-7 are ignored */ - acpigen_emit_byte(readwrite ? 0x01 : 0x00); - acpigen_emit_byte(base & 0xff); - acpigen_emit_byte((base >> 8) & 0xff); - acpigen_emit_byte((base >> 16) & 0xff); - acpigen_emit_byte((base >> 24) & 0xff); - acpigen_emit_byte(size & 0xff); - acpigen_emit_byte((size >> 8) & 0xff); - acpigen_emit_byte((size >> 16) & 0xff); - acpigen_emit_byte((size >> 24) & 0xff); -} - -void acpigen_write_register(acpi_addr_t *addr) -{ - acpigen_emit_byte(0x82); /* Register Descriptor */ - acpigen_emit_byte(0x0c); /* Register Length 7:0 */ - acpigen_emit_byte(0x00); /* Register Length 15:8 */ - acpigen_emit_byte(addr->space_id); /* Address Space ID */ - acpigen_emit_byte(addr->bit_width); /* Register Bit Width */ - acpigen_emit_byte(addr->bit_offset); /* Register Bit Offset */ - acpigen_emit_byte(addr->resv); /* Register Access Size */ - acpigen_emit_byte(addr->addrl & 0xff); /* Register Address Low */ - acpigen_emit_byte((addr->addrl >> 8) & 0xff); - acpigen_emit_byte((addr->addrl >> 16) & 0xff); - acpigen_emit_byte((addr->addrl >> 24) & 0xff); - acpigen_emit_byte(addr->addrh & 0xff); /* Register Address High */ - acpigen_emit_byte((addr->addrh >> 8) & 0xff); - acpigen_emit_byte((addr->addrh >> 16) & 0xff); - acpigen_emit_byte((addr->addrh >> 24) & 0xff); -} - -void acpigen_write_irq(u16 mask) -{ - /* - * acpi 3.0b section 6.4.2.1: IRQ Descriptor - * Byte 0: - * Bit7 : 0 => small item - * Bit6-3: 0100 (0x4) => IRQ port descriptor - * Bit2-0: 010 (0x2) => 2 Bytes long - */ - acpigen_emit_byte(0x22); - acpigen_emit_byte(mask & 0xff); - acpigen_emit_byte((mask >> 8) & 0xff); -} - -void acpigen_write_io16(u16 min, u16 max, u8 align, u8 len, u8 decode16) -{ - /* - * acpi 4.0 section 6.4.2.6: I/O Port Descriptor - * Byte 0: - * Bit7 : 0 => small item - * Bit6-3: 1000 (0x8) => I/O port descriptor - * Bit2-0: 111 (0x7) => 7 Bytes long - */ - acpigen_emit_byte(0x47); - /* Does the device decode all 16 or just 10 bits? */ - /* bit1-7 are ignored */ - acpigen_emit_byte(decode16 ? 0x01 : 0x00); - /* minimum base address the device may be configured for */ - acpigen_emit_byte(min & 0xff); - acpigen_emit_byte((min >> 8) & 0xff); - /* maximum base address the device may be configured for */ - acpigen_emit_byte(max & 0xff); - acpigen_emit_byte((max >> 8) & 0xff); - /* alignment for min base */ - acpigen_emit_byte(align & 0xff); - acpigen_emit_byte(len & 0xff); -} - -void acpigen_write_resourcetemplate_header(void) -{ - /* - * A ResourceTemplate() is a Buffer() with a - * (Byte|Word|DWord) containing the length, followed by one or more - * resource items, terminated by the end tag. - * (small item 0xf, len 1) - */ - acpigen_emit_byte(0x11); /* Buffer opcode */ - acpigen_write_len_f(); - acpigen_emit_byte(0x0b); /* Word opcode */ - len_stack[ltop++] = acpigen_get_current(); - acpigen_emit_byte(0x00); - acpigen_emit_byte(0x00); -} - -void acpigen_write_resourcetemplate_footer(void) -{ - char *p = len_stack[--ltop]; - int len; - /* - * end tag (acpi 4.0 Section 6.4.2.8) - * 0x79 - * 0x00 is treated as a good checksum according to the spec - * and is what iasl generates. - */ - acpigen_emit_byte(0x79); - acpigen_emit_byte(0x00); - - len = gencurrent - p; - - /* patch len word */ - p[0] = len & 0xff; - p[1] = (len >> 8) & 0xff; - /* patch len field */ - acpigen_pop_len(); -} - -static void acpigen_add_mainboard_rsvd_mem32(void *gp, struct device *dev, - struct resource *res) -{ - acpigen_write_mem32fixed(0, res->base, res->size); -} - -static void acpigen_add_mainboard_rsvd_io(void *gp, struct device *dev, - struct resource *res) -{ - resource_t base = res->base; - resource_t size = res->size; - while (size > 0) { - resource_t sz = size > 255 ? 255 : size; - acpigen_write_io16(base, base, 0, sz, 1); - size -= sz; - base += sz; - } -} - -void acpigen_write_mainboard_resource_template(void) -{ - acpigen_write_resourcetemplate_header(); - - /* Add reserved memory ranges. */ - search_global_resources( - IORESOURCE_MEM | IORESOURCE_RESERVE, - IORESOURCE_MEM | IORESOURCE_RESERVE, - acpigen_add_mainboard_rsvd_mem32, 0); - - /* Add reserved io ranges. */ - search_global_resources( - IORESOURCE_IO | IORESOURCE_RESERVE, - IORESOURCE_IO | IORESOURCE_RESERVE, - acpigen_add_mainboard_rsvd_io, 0); - - acpigen_write_resourcetemplate_footer(); -} - -void acpigen_write_mainboard_resources(const char *scope, const char *name) -{ - acpigen_write_scope(scope); - acpigen_write_name(name); - acpigen_write_mainboard_resource_template(); - acpigen_pop_len(); -} - -static int hex2bin(const char c) -{ - if (c >= 'A' && c <= 'F') - return c - 'A' + 10; - if (c >= 'a' && c <= 'f') - return c - 'a' + 10; - return c - '0'; -} - -void acpigen_emit_eisaid(const char *eisaid) -{ - u32 compact = 0; - - /* Clamping individual values would be better but - there is a disagreement over what is a valid - EISA id, so accept anything and don't clamp, - parent code should create a valid EISAid. - */ - compact |= (eisaid[0] - 'A' + 1) << 26; - compact |= (eisaid[1] - 'A' + 1) << 21; - compact |= (eisaid[2] - 'A' + 1) << 16; - compact |= hex2bin(eisaid[3]) << 12; - compact |= hex2bin(eisaid[4]) << 8; - compact |= hex2bin(eisaid[5]) << 4; - compact |= hex2bin(eisaid[6]); - - acpigen_emit_byte(0xc); - acpigen_emit_byte((compact >> 24) & 0xff); - acpigen_emit_byte((compact >> 16) & 0xff); - acpigen_emit_byte((compact >> 8) & 0xff); - acpigen_emit_byte(compact & 0xff); -} diff --git a/src/arch/x86/boot/boot.c b/src/arch/x86/boot/boot.c deleted file mode 100644 index 7eb87fbef6..0000000000 --- a/src/arch/x86/boot/boot.c +++ /dev/null @@ -1,210 +0,0 @@ -#include -#include -#include -#include -#include -#include - -/* When the ramstage is relocatable the elf loading ensures an elf image cannot - * be loaded over the ramstage code. */ -static void jmp_payload_no_bounce_buffer(void *entry) -{ - /* Jump to kernel */ - __asm__ __volatile__( - " cld \n\t" - /* Now jump to the loaded image */ - " call *%0\n\t" - - /* The loaded image returned? */ - " cli \n\t" - " cld \n\t" - - :: - "r" (entry) - ); -} - -static void jmp_payload(void *entry, unsigned long buffer, unsigned long size) -{ - unsigned long lb_start, lb_size; - - lb_start = (unsigned long)&_program; - lb_size = _program_size; - - printk(BIOS_SPEW, "entry = 0x%08lx\n", (unsigned long)entry); - printk(BIOS_SPEW, "lb_start = 0x%08lx\n", lb_start); - printk(BIOS_SPEW, "lb_size = 0x%08lx\n", lb_size); - printk(BIOS_SPEW, "buffer = 0x%08lx\n", buffer); - - /* Jump to kernel */ - __asm__ __volatile__( - " cld \n\t" -#ifdef __x86_64__ - /* switch back to 32-bit mode */ - " push %4\n\t" - " push %3\n\t" - " push %2\n\t" - " push %1\n\t" - " push %0\n\t" - - ".intel_syntax noprefix\n\t" - /* use iret to switch to 32-bit code segment */ - " xor rax,rax\n\t" - " mov ax, ss\n\t" - " push rax\n\t" - " mov rax, rsp\n\t" - " add rax, 8\n\t" - " push rax\n\t" - " pushfq\n\t" - " push 0x10\n\t" - " lea rax,[rip+3]\n\t" - " push rax\n\t" - " iretq\n\t" - ".code32\n\t" - /* disable paging */ - " mov eax, cr0\n\t" - " btc eax, 31\n\t" - " mov cr0, eax\n\t" - /* disable long mode */ - " mov ecx, 0xC0000080\n\t" - " rdmsr\n\t" - " btc eax, 8\n\t" - " wrmsr\n\t" - - " pop eax\n\t" - " add esp, 4\n\t" - " pop ebx\n\t" - " add esp, 4\n\t" - " pop ecx\n\t" - - " add esp, 4\n\t" - " pop edx\n\t" - " add esp, 4\n\t" - " pop esi\n\t" - " add esp, 4\n\t" - - ".att_syntax prefix\n\t" -#endif - - /* Save the callee save registers... */ - " pushl %%esi\n\t" - " pushl %%edi\n\t" - " pushl %%ebx\n\t" - /* Save the parameters I was passed */ -#ifdef __x86_64__ - " pushl $0\n\t" /* 20 adjust */ - " pushl %%eax\n\t" /* 16 lb_start */ - " pushl %%ebx\n\t" /* 12 buffer */ - " pushl %%ecx\n\t" /* 8 lb_size */ - " pushl %%edx\n\t" /* 4 entry */ - " pushl %%esi\n\t" /* 0 elf_boot_notes */ -#else - " pushl $0\n\t" /* 20 adjust */ - " pushl %0\n\t" /* 16 lb_start */ - " pushl %1\n\t" /* 12 buffer */ - " pushl %2\n\t" /* 8 lb_size */ - " pushl %3\n\t" /* 4 entry */ - " pushl %4\n\t" /* 0 elf_boot_notes */ - -#endif - /* Compute the adjustment */ - " xorl %%eax, %%eax\n\t" - " subl 16(%%esp), %%eax\n\t" - " addl 12(%%esp), %%eax\n\t" - " addl 8(%%esp), %%eax\n\t" - " movl %%eax, 20(%%esp)\n\t" - /* Place a copy of coreboot in its new location */ - /* Move ``longs'' the coreboot size is 4 byte aligned */ - " movl 12(%%esp), %%edi\n\t" - " addl 8(%%esp), %%edi\n\t" - " movl 16(%%esp), %%esi\n\t" - " movl 8(%%esp), %%ecx\n\n" - " shrl $2, %%ecx\n\t" - " rep movsl\n\t" - - /* Adjust the stack pointer to point into the new coreboot image */ - " addl 20(%%esp), %%esp\n\t" - /* Adjust the instruction pointer to point into the new coreboot image */ - " movl $1f, %%eax\n\t" - " addl 20(%%esp), %%eax\n\t" - " jmp *%%eax\n\t" - "1: \n\t" - - /* Copy the coreboot bounce buffer over coreboot */ - /* Move ``longs'' the coreboot size is 4 byte aligned */ - " movl 16(%%esp), %%edi\n\t" - " movl 12(%%esp), %%esi\n\t" - " movl 8(%%esp), %%ecx\n\t" - " shrl $2, %%ecx\n\t" - " rep movsl\n\t" - - /* Now jump to the loaded image */ - " movl %5, %%eax\n\t" - " movl 0(%%esp), %%ebx\n\t" - " call *4(%%esp)\n\t" - - /* The loaded image returned? */ - " cli \n\t" - " cld \n\t" - - /* Copy the saved copy of coreboot where coreboot runs */ - /* Move ``longs'' the coreboot size is 4 byte aligned */ - " movl 16(%%esp), %%edi\n\t" - " movl 12(%%esp), %%esi\n\t" - " addl 8(%%esp), %%esi\n\t" - " movl 8(%%esp), %%ecx\n\t" - " shrl $2, %%ecx\n\t" - " rep movsl\n\t" - - /* Adjust the stack pointer to point into the old coreboot image */ - " subl 20(%%esp), %%esp\n\t" - - /* Adjust the instruction pointer to point into the old coreboot image */ - " movl $1f, %%eax\n\t" - " subl 20(%%esp), %%eax\n\t" - " jmp *%%eax\n\t" - "1: \n\t" - - /* Drop the parameters I was passed */ - " addl $24, %%esp\n\t" - - /* Restore the callee save registers */ - " popl %%ebx\n\t" - " popl %%edi\n\t" - " popl %%esi\n\t" -#ifdef __x86_64__ - ".code64\n\t" -#endif - :: - "ri" (lb_start), "ri" (buffer), "ri" (lb_size), - "ri" (entry), - "ri"(0), "ri" (0) - ); -} - -static void try_payload(struct prog *prog) -{ - if (prog_type(prog) == ASSET_PAYLOAD) { - if (IS_ENABLED(CONFIG_RELOCATABLE_RAMSTAGE)) - jmp_payload_no_bounce_buffer(prog_entry(prog)); - else - jmp_payload(prog_entry(prog), - (uintptr_t)prog_start(prog), - prog_size(prog)); - } -} - -void arch_prog_run(struct prog *prog) -{ - if (ENV_RAMSTAGE) - try_payload(prog); - __asm__ volatile ( -#ifdef __x86_64__ - "jmp *%%rdi\n" -#else - "jmp *%%edi\n" -#endif - - :: "D"(prog_entry(prog)) - ); -} diff --git a/src/arch/x86/boot/cbmem.c b/src/arch/x86/boot/cbmem.c deleted file mode 100644 index e279db960c..0000000000 --- a/src/arch/x86/boot/cbmem.c +++ /dev/null @@ -1,76 +0,0 @@ -/* - * This file is part of the coreboot project. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; version 2 of the License. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc. - */ - -#include -#include -#include -#include - -#if IS_ENABLED(CONFIG_LATE_CBMEM_INIT) - -#if !defined(__PRE_RAM__) -void __attribute__((weak)) backup_top_of_ram(uint64_t ramtop) -{ - /* Do nothing. Chipset may have implementation to save ramtop in NVRAM. */ -} - -static void *ramtop_pointer; - -void set_top_of_ram(uint64_t ramtop) -{ - backup_top_of_ram(ramtop); - ramtop_pointer = (void *)(uintptr_t)ramtop; -} - -static inline void *saved_ramtop(void) -{ - return ramtop_pointer; -} -#else -static inline void *saved_ramtop(void) -{ - return NULL; -} -#endif /* !__PRE_RAM__ */ - -unsigned long __attribute__((weak)) get_top_of_ram(void) -{ - return 0; -} - -void *cbmem_top(void) -{ - /* Top of cbmem is at lowest usable DRAM address below 4GiB. */ - void *ptr = saved_ramtop(); - - if (ptr != NULL) - return ptr; - - return (void *)get_top_of_ram(); -} - -#endif /* LATE_CBMEM_INIT */ - -/* Something went wrong, our high memory area got wiped */ -void cbmem_fail_resume(void) -{ -#if !defined(__PRE_RAM__) && IS_ENABLED(CONFIG_HAVE_ACPI_RESUME) - /* ACPI resume needs to be cleared in the fail-to-recover case, but that - * condition is only handled during ramstage. */ - acpi_fail_wakeup(); -#endif -} diff --git a/src/arch/x86/boot/gdt.c b/src/arch/x86/boot/gdt.c deleted file mode 100644 index a21fab24ad..0000000000 --- a/src/arch/x86/boot/gdt.c +++ /dev/null @@ -1,62 +0,0 @@ -/* - * This file is part of the coreboot project. - * - * Copyright (C) 2008-2009 coresystems GmbH - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; version 2 of the License. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc. - */ - -#include -#include -#include -#include -#include - -/* i386 lgdt argument */ -struct gdtarg { - u16 limit; -#ifdef __x86_64__ - u64 base; -#else - u32 base; -#endif -} __attribute__((packed)); - -/* Copy GDT to new location and reload it. - * FIXME: We only do this for BSP CPU. - */ -static void move_gdt(int is_recovery) -{ - void *newgdt; - u16 num_gdt_bytes = (uintptr_t)&gdt_end - (uintptr_t)&gdt; - struct gdtarg gdtarg; - - newgdt = cbmem_find(CBMEM_ID_GDT); - if (!newgdt) { - newgdt = cbmem_add(CBMEM_ID_GDT, ALIGN(num_gdt_bytes, 512)); - if (!newgdt) { - printk(BIOS_ERR, "Error: Could not relocate GDT.\n"); - return; - } - printk(BIOS_DEBUG, "Moving GDT to %p...", newgdt); - memcpy((void*)newgdt, &gdt, num_gdt_bytes); - } - - gdtarg.base = (uintptr_t)newgdt; - gdtarg.limit = num_gdt_bytes - 1; - - __asm__ __volatile__ ("lgdt %0\n\t" : : "m" (gdtarg)); - printk(BIOS_DEBUG, "ok\n"); -} -RAMSTAGE_CBMEM_INIT_HOOK(move_gdt) diff --git a/src/arch/x86/boot/mpspec.c b/src/arch/x86/boot/mpspec.c deleted file mode 100644 index 1a0ac31fd0..0000000000 --- a/src/arch/x86/boot/mpspec.c +++ /dev/null @@ -1,597 +0,0 @@ -/* - * This file is part of the coreboot project. - * - * Copyright (C) 2014 Sage Electronic Engineering, LLC. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; version 2 of the License. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc. - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include - -/* Initialize the specified "mc" struct with initial values. */ -void mptable_init(struct mp_config_table *mc, u32 lapic_addr) -{ - int i; - - memset(mc, 0, sizeof(*mc)); - - memcpy(mc->mpc_signature, MPC_SIGNATURE, 4); - - mc->mpc_length = sizeof(*mc); /* Initially just the header size. */ - mc->mpc_spec = 0x04; /* MultiProcessor specification 1.4 */ - mc->mpc_checksum = 0; /* Not yet computed. */ - mc->mpc_oemptr = 0; - mc->mpc_oemsize = 0; - mc->mpc_entry_count = 0; /* No entries yet... */ - mc->mpc_lapic = lapic_addr; - mc->mpe_length = 0; - mc->mpe_checksum = 0; - mc->reserved = 0; - - strncpy(mc->mpc_oem, CONFIG_MAINBOARD_VENDOR, 8); - strncpy(mc->mpc_productid, CONFIG_MAINBOARD_PART_NUMBER, 12); - - /* - * The oem/productid fields are exactly 8/12 bytes long. If the resp. - * entry is shorter, the remaining bytes are filled with spaces. - */ - for (i = MIN(strlen(CONFIG_MAINBOARD_VENDOR), 8); i < 8; i++) - mc->mpc_oem[i] = ' '; - for (i = MIN(strlen(CONFIG_MAINBOARD_PART_NUMBER), 12); i < 12; i++) - mc->mpc_productid[i] = ' '; -} - -static unsigned char smp_compute_checksum(void *v, int len) -{ - unsigned char *bytes; - unsigned char checksum; - int i; - bytes = v; - checksum = 0; - for(i = 0; i < len; i++) { - checksum -= bytes[i]; - } - return checksum; -} - -static void *smp_write_floating_table_physaddr(uintptr_t addr, uintptr_t mpf_physptr, unsigned int virtualwire) -{ - struct intel_mp_floating *mf; - void *v; - - v = (void *)addr; - mf = v; - mf->mpf_signature[0] = '_'; - mf->mpf_signature[1] = 'M'; - mf->mpf_signature[2] = 'P'; - mf->mpf_signature[3] = '_'; - mf->mpf_physptr = mpf_physptr; - mf->mpf_length = 1; - mf->mpf_specification = 4; - mf->mpf_checksum = 0; - mf->mpf_feature1 = 0; - mf->mpf_feature2 = virtualwire?MP_FEATURE_PIC:MP_FEATURE_VIRTUALWIRE; - mf->mpf_feature3 = 0; - mf->mpf_feature4 = 0; - mf->mpf_feature5 = 0; - mf->mpf_checksum = smp_compute_checksum(mf, mf->mpf_length*16); - return v; -} - -void *smp_write_floating_table(unsigned long addr, unsigned int virtualwire) -{ - /* 16 byte align the table address */ - addr = (addr + 0xf) & (~0xf); - return smp_write_floating_table_physaddr(addr, addr + SMP_FLOATING_TABLE_LEN, virtualwire); -} - -void *smp_next_mpc_entry(struct mp_config_table *mc) -{ - void *v; - v = (void *)(((char *)mc) + mc->mpc_length); - - return v; -} -static void smp_add_mpc_entry(struct mp_config_table *mc, u16 length) -{ - mc->mpc_length += length; - mc->mpc_entry_count++; -} - -void *smp_next_mpe_entry(struct mp_config_table *mc) -{ - void *v; - v = (void *)(((char *)mc) + mc->mpc_length + mc->mpe_length); - - return v; -} -static void smp_add_mpe_entry(struct mp_config_table *mc, mpe_t mpe) -{ - mc->mpe_length += mpe->mpe_length; -} - -/* - * Type 0: Processor Entries: - * Entry Type, LAPIC ID, LAPIC Version, CPU Flags EN/BP, - * CPU Signature (Stepping, Model, Family), Feature Flags - */ -void smp_write_processor(struct mp_config_table *mc, - u8 apicid, u8 apicver, u8 cpuflag, - u32 cpufeature, u32 featureflag) -{ - struct mpc_config_processor *mpc; - mpc = smp_next_mpc_entry(mc); - memset(mpc, '\0', sizeof(*mpc)); - mpc->mpc_type = MP_PROCESSOR; - mpc->mpc_apicid = apicid; - mpc->mpc_apicver = apicver; - mpc->mpc_cpuflag = cpuflag; - mpc->mpc_cpufeature = cpufeature; - mpc->mpc_featureflag = featureflag; - smp_add_mpc_entry(mc, sizeof(*mpc)); -} - -/* - * If we assume a symmetric processor configuration we can - * get all of the information we need to write the processor - * entry from the bootstrap processor. - * Plus I don't think linux really even cares. - * Having the proper apicid's in the table so the non-bootstrap - * processors can be woken up should be enough. - */ -void smp_write_processors(struct mp_config_table *mc) -{ - int boot_apic_id; - int order_id; - unsigned apic_version; - unsigned cpu_features; - unsigned cpu_feature_flags; - struct cpuid_result result; - struct device *cpu; - - boot_apic_id = lapicid(); - apic_version = lapic_read(LAPIC_LVR) & 0xff; - result = cpuid(1); - cpu_features = result.eax; - cpu_feature_flags = result.edx; - /* order the output of the cpus to fix a bug in kernel 2.6.11 */ - for(order_id = 0;order_id <256; order_id++) { - for(cpu = all_devices; cpu; cpu = cpu->next) { - unsigned long cpu_flag; - if ((cpu->path.type != DEVICE_PATH_APIC) || - (cpu->bus->dev->path.type != DEVICE_PATH_CPU_CLUSTER)) - continue; - - if (!cpu->enabled) - continue; - - cpu_flag = MPC_CPU_ENABLED; - - if (boot_apic_id == cpu->path.apic.apic_id) - cpu_flag = MPC_CPU_ENABLED | MPC_CPU_BOOTPROCESSOR; - - if(cpu->path.apic.apic_id == order_id) { - smp_write_processor(mc, - cpu->path.apic.apic_id, apic_version, - cpu_flag, cpu_features, cpu_feature_flags - ); - break; - } - } - } -} - -/* - * Type 1: Bus Entries: - * Entry Type, Bus ID, Bus Type - */ -static void smp_write_bus(struct mp_config_table *mc, - u8 id, const char *bustype) -{ - struct mpc_config_bus *mpc; - mpc = smp_next_mpc_entry(mc); - memset(mpc, '\0', sizeof(*mpc)); - mpc->mpc_type = MP_BUS; - mpc->mpc_busid = id; - memcpy(mpc->mpc_bustype, bustype, sizeof(mpc->mpc_bustype)); - smp_add_mpc_entry(mc, sizeof(*mpc)); -} - -/* - * Type 2: I/O APIC Entries: - * Entry Type, APIC ID, Version, - * APIC Flags:EN, Address - */ -void smp_write_ioapic(struct mp_config_table *mc, - u8 id, u8 ver, void *apicaddr) -{ - struct mpc_config_ioapic *mpc; - mpc = smp_next_mpc_entry(mc); - memset(mpc, '\0', sizeof(*mpc)); - mpc->mpc_type = MP_IOAPIC; - mpc->mpc_apicid = id; - mpc->mpc_apicver = ver; - mpc->mpc_flags = MPC_APIC_USABLE; - mpc->mpc_apicaddr = apicaddr; - smp_add_mpc_entry(mc, sizeof(*mpc)); -} - -/* - * Type 3: I/O Interrupt Table Entries: - * Entry Type, Int Type, Int Polarity, Int Level, - * Source Bus ID, Source Bus IRQ, Dest APIC ID, Dest PIN# - */ -void smp_write_intsrc(struct mp_config_table *mc, - u8 irqtype, u16 irqflag, - u8 srcbus, u8 srcbusirq, - u8 dstapic, u8 dstirq) -{ - struct mpc_config_intsrc *mpc; - mpc = smp_next_mpc_entry(mc); - memset(mpc, '\0', sizeof(*mpc)); - mpc->mpc_type = MP_INTSRC; - mpc->mpc_irqtype = irqtype; - mpc->mpc_irqflag = irqflag; - mpc->mpc_srcbus = srcbus; - mpc->mpc_srcbusirq = srcbusirq; - mpc->mpc_dstapic = dstapic; - mpc->mpc_dstirq = dstirq; - smp_add_mpc_entry(mc, sizeof(*mpc)); -#ifdef DEBUG_MPTABLE - printk(BIOS_DEBUG, "add intsrc srcbus 0x%x srcbusirq 0x%x, dstapic 0x%x, dstirq 0x%x\n", - srcbus, srcbusirq, dstapic, dstirq); - hexdump(__func__, mpc, sizeof(*mpc)); -#endif -} - -/* - * Type 3: I/O Interrupt Table Entries for PCI Devices: - * This has the same fields as 'Type 3: I/O Interrupt Table Entries' - * but the Source Bus IRQ field has a slightly different - * definition: - * Bits 1-0: PIRQ pin: INT_A# = 0, INT_B# = 1, INT_C# = 2, INT_D# = 3 - * Bits 2-6: Originating PCI Device Number (Not its parent bridge device number) - * Bit 7: Reserved - */ -void smp_write_pci_intsrc(struct mp_config_table *mc, - u8 irqtype, u8 srcbus, u8 dev, u8 pirq, - u8 dstapic, u8 dstirq) -{ - u8 srcbusirq = (dev << 2) | pirq; - printk(BIOS_SPEW, "\tPCI srcbusirq = 0x%x from dev = 0x%x and pirq = %x\n", srcbusirq, dev, pirq); - smp_write_intsrc(mc, irqtype, MP_IRQ_TRIGGER_LEVEL|MP_IRQ_POLARITY_LOW, srcbus, - srcbusirq, dstapic, dstirq); -} - -void smp_write_intsrc_pci_bridge(struct mp_config_table *mc, - u8 irqtype, u16 irqflag, struct device *dev, - unsigned char dstapic, unsigned char *dstirq) -{ - struct device *child; - - int i; - int srcbus; - int slot; - - struct bus *link; - unsigned char dstirq_x[4]; - - for (link = dev->link_list; link; link = link->next) { - - child = link->children; - srcbus = link->secondary; - - while (child) { - if (child->path.type != DEVICE_PATH_PCI) - goto next; - - slot = (child->path.pci.devfn >> 3); - /* round pins */ - for (i = 0; i < 4; i++) - dstirq_x[i] = dstirq[(i + slot) % 4]; - - if ((child->class >> 16) != PCI_BASE_CLASS_BRIDGE) { - /* pci device */ - printk(BIOS_DEBUG, "route irq: %s\n", dev_path(child)); - for (i = 0; i < 4; i++) - smp_write_intsrc(mc, irqtype, irqflag, srcbus, (slot<<2)|i, dstapic, dstirq_x[i]); - goto next; - } - - switch (child->class>>8) { - case PCI_CLASS_BRIDGE_PCI: - case PCI_CLASS_BRIDGE_PCMCIA: - case PCI_CLASS_BRIDGE_CARDBUS: - printk(BIOS_DEBUG, "route irq bridge: %s\n", dev_path(child)); - smp_write_intsrc_pci_bridge(mc, irqtype, irqflag, child, dstapic, dstirq_x); - } - -next: - child = child->sibling; - } - - } -} - -/* - * Type 4: Local Interrupt Assignment Entries: - * Entry Type, Int Type, Int Polarity, Int Level, - * Source Bus ID, Source Bus IRQ, Dest LAPIC ID, - * Dest LAPIC LINTIN# - */ -void smp_write_lintsrc(struct mp_config_table *mc, - u8 irqtype, u16 irqflag, - u8 srcbusid, u8 srcbusirq, - u8 destapic, u8 destapiclint) -{ - struct mpc_config_lintsrc *mpc; - mpc = smp_next_mpc_entry(mc); - memset(mpc, '\0', sizeof(*mpc)); - mpc->mpc_type = MP_LINTSRC; - mpc->mpc_irqtype = irqtype; - mpc->mpc_irqflag = irqflag; - mpc->mpc_srcbusid = srcbusid; - mpc->mpc_srcbusirq = srcbusirq; - mpc->mpc_destapic = destapic; - mpc->mpc_destapiclint = destapiclint; - smp_add_mpc_entry(mc, sizeof(*mpc)); -} - -/* - * Type 128: System Address Space Mapping Entries - * Entry Type, Entry Length, Bus ID, Address Type, - * Address Base Lo/Hi, Address Length Lo/Hi - */ -void smp_write_address_space(struct mp_config_table *mc, - u8 busid, u8 address_type, - u32 address_base_low, u32 address_base_high, - u32 address_length_low, u32 address_length_high) -{ - struct mp_exten_system_address_space *mpe; - mpe = smp_next_mpe_entry(mc); - memset(mpe, '\0', sizeof(*mpe)); - mpe->mpe_type = MPE_SYSTEM_ADDRESS_SPACE; - mpe->mpe_length = sizeof(*mpe); - mpe->mpe_busid = busid; - mpe->mpe_address_type = address_type; - mpe->mpe_address_base_low = address_base_low; - mpe->mpe_address_base_high = address_base_high; - mpe->mpe_address_length_low = address_length_low; - mpe->mpe_address_length_high = address_length_high; - smp_add_mpe_entry(mc, (mpe_t)mpe); -} - -/* - * Type 129: Bus Hierarchy Descriptor Entry - * Entry Type, Entry Length, Bus ID, Bus Info, - * Parent Bus ID - */ -void smp_write_bus_hierarchy(struct mp_config_table *mc, - u8 busid, u8 bus_info, u8 parent_busid) -{ - struct mp_exten_bus_hierarchy *mpe; - mpe = smp_next_mpe_entry(mc); - memset(mpe, '\0', sizeof(*mpe)); - mpe->mpe_type = MPE_BUS_HIERARCHY; - mpe->mpe_length = sizeof(*mpe); - mpe->mpe_busid = busid; - mpe->mpe_bus_info = bus_info; - mpe->mpe_parent_busid = parent_busid; - smp_add_mpe_entry(mc, (mpe_t)mpe); -} - -/* - * Type 130: Compatibility Bus Address Space Modifier Entry - * Entry Type, Entry Length, Bus ID, Address Modifier - * Predefined Range List - */ -void smp_write_compatibility_address_space(struct mp_config_table *mc, - u8 busid, u8 address_modifier, - u32 range_list) -{ - struct mp_exten_compatibility_address_space *mpe; - mpe = smp_next_mpe_entry(mc); - memset(mpe, '\0', sizeof(*mpe)); - mpe->mpe_type = MPE_COMPATIBILITY_ADDRESS_SPACE; - mpe->mpe_length = sizeof(*mpe); - mpe->mpe_busid = busid; - mpe->mpe_address_modifier = address_modifier; - mpe->mpe_range_list = range_list; - smp_add_mpe_entry(mc, (mpe_t)mpe); -} - -void mptable_lintsrc(struct mp_config_table *mc, unsigned long bus_isa) -{ - smp_write_lintsrc(mc, mp_ExtINT, MP_IRQ_TRIGGER_EDGE|MP_IRQ_POLARITY_HIGH, bus_isa, 0x0, MP_APIC_ALL, 0x0); - smp_write_lintsrc(mc, mp_NMI, MP_IRQ_TRIGGER_EDGE|MP_IRQ_POLARITY_HIGH, bus_isa, 0x0, MP_APIC_ALL, 0x1); -} - -void mptable_add_isa_interrupts(struct mp_config_table *mc, unsigned long bus_isa, unsigned long apicid, int external_int2) -{ -/*I/O Ints: Type Trigger Polarity Bus ID IRQ APIC ID PIN# */ - smp_write_intsrc(mc, external_int2?mp_INT:mp_ExtINT, - MP_IRQ_TRIGGER_EDGE|MP_IRQ_POLARITY_HIGH, bus_isa, 0x0, apicid, 0x0); - smp_write_intsrc(mc, mp_INT, MP_IRQ_TRIGGER_EDGE|MP_IRQ_POLARITY_HIGH, bus_isa, 0x1, apicid, 0x1); - smp_write_intsrc(mc, external_int2?mp_ExtINT:mp_INT, - MP_IRQ_TRIGGER_EDGE|MP_IRQ_POLARITY_HIGH, bus_isa, 0x0, apicid, 0x2); - smp_write_intsrc(mc, mp_INT, MP_IRQ_TRIGGER_EDGE|MP_IRQ_POLARITY_HIGH, bus_isa, 0x3, apicid, 0x3); - smp_write_intsrc(mc, mp_INT, MP_IRQ_TRIGGER_EDGE|MP_IRQ_POLARITY_HIGH, bus_isa, 0x4, apicid, 0x4); - smp_write_intsrc(mc, mp_INT, MP_IRQ_TRIGGER_EDGE|MP_IRQ_POLARITY_HIGH, bus_isa, 0x6, apicid, 0x6); - smp_write_intsrc(mc, mp_INT, MP_IRQ_TRIGGER_EDGE|MP_IRQ_POLARITY_HIGH, bus_isa, 0x7, apicid, 0x7); - smp_write_intsrc(mc, mp_INT, MP_IRQ_TRIGGER_EDGE|MP_IRQ_POLARITY_HIGH, bus_isa, 0x8, apicid, 0x8); - smp_write_intsrc(mc, mp_INT, MP_IRQ_TRIGGER_EDGE|MP_IRQ_POLARITY_HIGH, bus_isa, 0x9, apicid, 0x9); - smp_write_intsrc(mc, mp_INT, MP_IRQ_TRIGGER_EDGE|MP_IRQ_POLARITY_HIGH, bus_isa, 0xa, apicid, 0xa); - smp_write_intsrc(mc, mp_INT, MP_IRQ_TRIGGER_EDGE|MP_IRQ_POLARITY_HIGH, bus_isa, 0xb, apicid, 0xb); - smp_write_intsrc(mc, mp_INT, MP_IRQ_TRIGGER_EDGE|MP_IRQ_POLARITY_HIGH, bus_isa, 0xc, apicid, 0xc); - smp_write_intsrc(mc, mp_INT, MP_IRQ_TRIGGER_EDGE|MP_IRQ_POLARITY_HIGH, bus_isa, 0xd, apicid, 0xd); - smp_write_intsrc(mc, mp_INT, MP_IRQ_TRIGGER_EDGE|MP_IRQ_POLARITY_HIGH, bus_isa, 0xe, apicid, 0xe); - smp_write_intsrc(mc, mp_INT, MP_IRQ_TRIGGER_EDGE|MP_IRQ_POLARITY_HIGH, bus_isa, 0xf, apicid, 0xf); -} - -void mptable_write_buses(struct mp_config_table *mc, int *max_pci_bus, int *isa_bus) { - int dummy, i, highest; - char buses[256]; - struct device *dev; - - if (!max_pci_bus) max_pci_bus = &dummy; - if (!isa_bus) isa_bus = &dummy; - - *max_pci_bus = 0; - highest = 0; - memset(buses, 0, sizeof(buses)); - - for (dev = all_devices; dev; dev = dev->next) { - struct bus *bus; - for (bus = dev->link_list; bus; bus = bus->next) { - if (bus->secondary > 255) { - printk(BIOS_ERR, "A bus claims to have a bus ID > 255?!? Aborting"); - return; - } - buses[bus->secondary] = 1; - if (highest < bus->secondary) highest = bus->secondary; - } - } - for (i=0; i <= highest; i++) { - if (buses[i]) { - smp_write_bus(mc, i, "PCI "); - *max_pci_bus = i; - } - } - *isa_bus = *max_pci_bus + 1; - smp_write_bus(mc, *isa_bus, "ISA "); -} - -void *mptable_finalize(struct mp_config_table *mc) -{ - mc->mpe_checksum = smp_compute_checksum(smp_next_mpc_entry(mc), mc->mpe_length); - mc->mpc_checksum = smp_compute_checksum(mc, mc->mpc_length); - printk(BIOS_DEBUG, "Wrote the mp table end at: %p - %p\n", mc, smp_next_mpe_entry(mc)); - return smp_next_mpe_entry(mc); -} - -unsigned long __attribute__((weak)) write_smp_table(unsigned long addr) -{ - struct drivers_generic_ioapic_config *ioapic_config; - struct mp_config_table *mc; - int isa_bus, pin, parentpin; - struct device *dev; - struct device *parent; - struct device *oldparent; - void *tmp, *v; - int isaioapic = -1, have_fixed_entries; - - v = smp_write_floating_table(addr, 0); - mc = (void *)(((char *)v) + SMP_FLOATING_TABLE_LEN); - - mptable_init(mc, LOCAL_APIC_ADDR); - - smp_write_processors(mc); - - mptable_write_buses(mc, NULL, &isa_bus); - - for(dev = all_devices; dev; dev = dev->next) { - if (dev->path.type != DEVICE_PATH_IOAPIC) - continue; - - if (!(ioapic_config = dev->chip_info)) { - printk(BIOS_ERR, "%s has no config, ignoring\n", dev_path(dev)); - continue; - } - smp_write_ioapic(mc, dev->path.ioapic.ioapic_id, - ioapic_config->version, - ioapic_config->base); - - if (ioapic_config->have_isa_interrupts) { - if (isaioapic >= 0) - printk(BIOS_ERR, "More than one IOAPIC with ISA interrupts?\n"); - else - isaioapic = dev->path.ioapic.ioapic_id; - } - } - - if (isaioapic >= 0) { - /* Legacy Interrupts */ - printk(BIOS_DEBUG, "Writing ISA IRQs\n"); - mptable_add_isa_interrupts(mc, isa_bus, isaioapic, 0); - } - - for(dev = all_devices; dev; dev = dev->next) { - - if (dev->path.type != DEVICE_PATH_PCI || !dev->enabled) - continue; - - have_fixed_entries = 0; - for (pin = 0; pin < 4; pin++) { - if (dev->pci_irq_info[pin].ioapic_dst_id) { - printk(BIOS_DEBUG, "fixed IRQ entry for: %s: INT%c# -> IOAPIC %d PIN %d\n", dev_path(dev), - pin + 'A', - dev->pci_irq_info[pin].ioapic_dst_id, - dev->pci_irq_info[pin].ioapic_irq_pin); - smp_write_intsrc(mc, mp_INT, - dev->pci_irq_info[pin].ioapic_flags, - dev->bus->secondary, - ((dev->path.pci.devfn & 0xf8) >> 1) | pin, - dev->pci_irq_info[pin].ioapic_dst_id, - dev->pci_irq_info[pin].ioapic_irq_pin); - have_fixed_entries = 1; - } - } - - if (!have_fixed_entries) { - pin = (dev->path.pci.devfn & 7) % 4; - oldparent = parent = dev; - while((parent = parent->bus->dev)) { - parentpin = (oldparent->path.pci.devfn >> 3) + (oldparent->path.pci.devfn & 7); - parentpin += dev->path.pci.devfn & 7; - parentpin += dev->path.pci.devfn >> 3; - parentpin %= 4; - - if (parent->pci_irq_info[parentpin].ioapic_dst_id) { - printk(BIOS_DEBUG, "automatic IRQ entry for %s: INT%c# -> IOAPIC %d PIN %d\n", - dev_path(dev), pin + 'A', - parent->pci_irq_info[parentpin].ioapic_dst_id, - parent->pci_irq_info[parentpin].ioapic_irq_pin); - smp_write_intsrc(mc, mp_INT, - parent->pci_irq_info[parentpin].ioapic_flags, - dev->bus->secondary, - ((dev->path.pci.devfn & 0xf8) >> 1) | pin, - parent->pci_irq_info[parentpin].ioapic_dst_id, - parent->pci_irq_info[parentpin].ioapic_irq_pin); - - break; - } - - if (parent->path.type == DEVICE_PATH_DOMAIN) { - printk(BIOS_WARNING, "no IRQ found for %s\n", dev_path(dev)); - break; - } - oldparent = parent; - } - } - } - - mptable_lintsrc(mc, isa_bus); - tmp = mptable_finalize(mc); - printk(BIOS_INFO, "MPTABLE len: %d\n", (unsigned int)((uintptr_t)tmp - - (uintptr_t)v)); - return (unsigned long)tmp; -} diff --git a/src/arch/x86/boot/pirq_routing.c b/src/arch/x86/boot/pirq_routing.c deleted file mode 100644 index 7fe20b25ab..0000000000 --- a/src/arch/x86/boot/pirq_routing.c +++ /dev/null @@ -1,208 +0,0 @@ -/* - * This file is part of the coreboot project. - * - * Copyright (C) 2012 Alexandru Gagniuc - * Copyright (C) 2010 Stefan Reinauer - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ -#include -#include -#include -#include - -#if CONFIG_DEBUG_PIRQ -static void check_pirq_routing_table(struct irq_routing_table *rt) -{ - uint8_t *addr = (uint8_t *)rt; - uint8_t sum=0; - int i; - - printk(BIOS_INFO, "Checking Interrupt Routing Table consistency...\n"); - - if (sizeof(struct irq_routing_table) != rt->size) { - printk(BIOS_WARNING, "Inconsistent Interrupt Routing Table size (0x%x/0x%x).\n", - (unsigned int) sizeof(struct irq_routing_table), - rt->size - ); - rt->size=sizeof(struct irq_routing_table); - } - - for (i = 0; i < rt->size; i++) - sum += addr[i]; - - printk(BIOS_DEBUG, "%s(): Interrupt Routing Table located at %p.\n", - __func__, addr); - - - sum = rt->checksum - sum; - - if (sum != rt->checksum) { - printk(BIOS_WARNING, "Interrupt Routing Table checksum is: 0x%02x but should be: 0x%02x.\n", - rt->checksum, sum); - rt->checksum = sum; - } - - if (rt->signature != PIRQ_SIGNATURE || rt->version != PIRQ_VERSION || - rt->size % 16 ) { - printk(BIOS_WARNING, "Interrupt Routing Table not valid.\n"); - return; - } - - sum = 0; - for (i=0; isize; i++) - sum += addr[i]; - - /* We're manually fixing the checksum above. This warning can probably - * never happen because if the target location is read-only this - * function would have bailed out earlier. - */ - if (sum) { - printk(BIOS_WARNING, "Checksum error in Interrupt Routing Table " - "could not be fixed.\n"); - } - - printk(BIOS_INFO, "done.\n"); -} - -static int verify_copy_pirq_routing_table(unsigned long addr, const struct irq_routing_table *routing_table) -{ - int i; - uint8_t *rt_orig, *rt_curr; - - rt_curr = (uint8_t*)addr; - rt_orig = (uint8_t*)routing_table; - printk(BIOS_INFO, "Verifying copy of Interrupt Routing Table at 0x%08lx... ", addr); - for (i = 0; i < routing_table->size; i++) { - if (*(rt_curr + i) != *(rt_orig + i)) { - printk(BIOS_INFO, "failed\n"); - return -1; - } - } - printk(BIOS_INFO, "done\n"); - - check_pirq_routing_table((struct irq_routing_table *)addr); - - return 0; -} -#endif - -#if CONFIG_PIRQ_ROUTE -static u8 pirq_get_next_free_irq(u8* pirq, u16 bitmap) -{ - int i, link; - u8 irq = 0; - for (i = 2; i <= 15; i++) - { - /* Can we assign this IRQ ? */ - if (!((bitmap >> i) & 1)) - continue; - /* We can, Now let's assume we can use this IRQ */ - irq = i; - /* And assume we have not yet routed it */ - int already_routed = 0; - /* Have we already routed it ? */ - for(link = 0; link < CONFIG_MAX_PIRQ_LINKS; link++) { - if (pirq[link] == irq) { - already_routed = 1; - break; - } - } - /* If it's not yet routed, use it */ - if(!already_routed) - break; - /* But if it was already routed, try the next one */ - continue; - } - /* Now we got our IRQ */ - return irq; -} - -static void pirq_route_irqs(unsigned long addr) -{ - int i, intx, num_entries; - unsigned char irq_slot[MAX_INTX_ENTRIES]; - unsigned char pirq[CONFIG_MAX_PIRQ_LINKS]; - struct irq_routing_table *pirq_tbl; - - memset(pirq, 0, CONFIG_MAX_PIRQ_LINKS); - - pirq_tbl = (struct irq_routing_table *)(addr); - num_entries = (pirq_tbl->size - 32) / 16; - - /* Set PCI IRQs. */ - for (i = 0; i < num_entries; i++) { - - printk(BIOS_DEBUG, "PIRQ Entry %d Dev/Fn: %X Slot: %d\n", i, - pirq_tbl->slots[i].devfn >> 3, pirq_tbl->slots[i].slot); - - for (intx = 0; intx < MAX_INTX_ENTRIES; intx++) { - - int link = pirq_tbl->slots[i].irq[intx].link; - int bitmap = pirq_tbl->slots[i].irq[intx].bitmap; - int irq = 0; - - printk(BIOS_DEBUG, "INT: %c link: %x bitmap: %x ", - 'A' + intx, link, bitmap); - - if (!bitmap|| !link || link > CONFIG_MAX_PIRQ_LINKS) { - - printk(BIOS_DEBUG, "not routed\n"); - irq_slot[intx] = irq; - continue; - } - - /* yet not routed */ - if (!pirq[link - 1]) - { - irq = pirq_get_next_free_irq(pirq, bitmap); - if (irq) - pirq[link - 1] = irq; - } - else - irq = pirq[link - 1]; - - printk(BIOS_DEBUG, "IRQ: %d\n", irq); - irq_slot[intx] = irq; - } - - /* Bus, device, slots IRQs for {A,B,C,D}. */ - pci_assign_irqs(pirq_tbl->slots[i].bus, - pirq_tbl->slots[i].devfn >> 3, irq_slot); - } - - for(i = 0; i < CONFIG_MAX_PIRQ_LINKS; i++) - printk(BIOS_DEBUG, "PIRQ%c: %d\n", i + 'A', pirq[i]); - - pirq_assign_irqs(pirq); -} -#endif - -unsigned long copy_pirq_routing_table(unsigned long addr, const struct irq_routing_table *routing_table) -{ - /* Align the table to be 16 byte aligned. */ - addr = ALIGN(addr, 16); - - /* This table must be between 0xf0000 & 0x100000 */ - printk(BIOS_INFO, "Copying Interrupt Routing Table to 0x%08lx... ", addr); - memcpy((void *)addr, routing_table, routing_table->size); - printk(BIOS_INFO, "done.\n"); -#if CONFIG_DEBUG_PIRQ - verify_copy_pirq_routing_table(addr, routing_table); -#endif -#if CONFIG_PIRQ_ROUTE - pirq_route_irqs(addr); -#endif - return addr + routing_table->size; -} diff --git a/src/arch/x86/boot/smbios.c b/src/arch/x86/boot/smbios.c deleted file mode 100644 index a1f05daeaf..0000000000 --- a/src/arch/x86/boot/smbios.c +++ /dev/null @@ -1,581 +0,0 @@ -/* - * This file is part of the coreboot project. - * - * Copyright (C) 2015 Timothy Pearson , Raptor Engineering - * Copyright (C) 2011 Sven Schnelle - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation; version 2 of - * the License. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc. - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#if CONFIG_CHROMEOS -#include -#endif - -static u8 smbios_checksum(u8 *p, u32 length) -{ - u8 ret = 0; - while (length--) - ret += *p++; - return -ret; -} - - -int smbios_add_string(char *start, const char *str) -{ - int i = 1; - char *p = start; - - for(;;) { - if (!*p) { - strcpy(p, str); - p += strlen(str); - *p++ = '\0'; - *p++ = '\0'; - return i; - } - - if (!strcmp(p, str)) - return i; - - p += strlen(p)+1; - i++; - } -} - -int smbios_string_table_len(char *start) -{ - char *p = start; - int i, len = 0; - - while(*p) { - i = strlen(p) + 1; - p += i; - len += i; - } - return len + 1; -} - -static int smbios_cpu_vendor(char *start) -{ - char tmp[13] = "Unknown"; - u32 *_tmp = (u32 *)tmp; - struct cpuid_result res; - - if (cpu_have_cpuid()) { - res = cpuid(0); - _tmp[0] = res.ebx; - _tmp[1] = res.edx; - _tmp[2] = res.ecx; - tmp[12] = '\0'; - } - - return smbios_add_string(start, tmp); -} - -static int smbios_processor_name(char *start) -{ - char tmp[49] = "Unknown Processor Name"; - u32 *_tmp = (u32 *)tmp; - struct cpuid_result res; - int i; - - if (cpu_have_cpuid()) { - res = cpuid(0x80000000); - if (res.eax >= 0x80000004) { - for (i = 0; i < 3; i++) { - res = cpuid(0x80000002 + i); - _tmp[i * 4 + 0] = res.eax; - _tmp[i * 4 + 1] = res.ebx; - _tmp[i * 4 + 2] = res.ecx; - _tmp[i * 4 + 3] = res.edx; - } - tmp[48] = 0; - } - } - return smbios_add_string(start, tmp); -} - -/* this function will fill the corresponding manufacturer */ -void smbios_fill_dimm_manufacturer_from_id(uint16_t mod_id, struct smbios_type17 *t) -{ - switch (mod_id) { - case 0x987f: - t->manufacturer = smbios_add_string(t->eos, - "Hynix"); - break; - case 0xad80: - t->manufacturer = smbios_add_string(t->eos, - "Hynix/Hyundai"); - break; - case 0xce80: - t->manufacturer = smbios_add_string(t->eos, - "Samsung"); - break; - case 0xfe02: - t->manufacturer = smbios_add_string(t->eos, - "Elpida"); - break; - case 0xff2c: - t->manufacturer = smbios_add_string(t->eos, - "Micron"); - break; - default: { - char string_buffer[256]; - snprintf(string_buffer, sizeof(string_buffer), - "Unknown (%x)", mod_id); - t->manufacturer = smbios_add_string(t->eos, - string_buffer); - break; - } - } -} - -static int create_smbios_type17_for_dimm(struct dimm_info *dimm, - unsigned long *current, int *handle) -{ - struct smbios_type17 *t = (struct smbios_type17 *)*current; - uint8_t length; - char locator[40]; - - memset(t, 0, sizeof(struct smbios_type17)); - t->memory_type = dimm->ddr_type; - t->clock_speed = dimm->ddr_frequency; - t->speed = dimm->ddr_frequency; - t->type = SMBIOS_MEMORY_DEVICE; - t->size = dimm->dimm_size; - t->data_width = 8 * (1 << (dimm->bus_width & 0x7)); - t->total_width = t->data_width + 8 * ((dimm->bus_width & 0x18) >> 3); - - switch (dimm->mod_type) { - case SPD_RDIMM: - case SPD_MINI_RDIMM: - t->form_factor = MEMORY_FORMFACTOR_RIMM; - break; - case SPD_UDIMM: - case SPD_MICRO_DIMM: - case SPD_MINI_UDIMM: - t->form_factor = MEMORY_FORMFACTOR_DIMM; - break; - case SPD_SODIMM: - t->form_factor = MEMORY_FORMFACTOR_SODIMM; - break; - default: - t->form_factor = MEMORY_FORMFACTOR_UNKNOWN; - break; - } - - smbios_fill_dimm_manufacturer_from_id(dimm->mod_id, t); - /* put '\0' in the end of data */ - length = sizeof(dimm->serial); - dimm->serial[length - 1] = '\0'; - if (dimm->serial[0] == 0) - t->serial_number = smbios_add_string(t->eos, "None"); - else - t->serial_number = smbios_add_string(t->eos, - (const char *)dimm->serial); - - snprintf(locator, sizeof(locator), "Channel-%d-DIMM-%d", - dimm->channel_num, dimm->dimm_num); - t->device_locator = smbios_add_string(t->eos, locator); - - snprintf(locator, sizeof(locator), "BANK %d", dimm->bank_locator); - t->bank_locator = smbios_add_string(t->eos, locator); - - /* put '\0' in the end of data */ - length = sizeof(dimm->module_part_number); - dimm->module_part_number[length - 1] = '\0'; - t->part_number = smbios_add_string(t->eos, - (const char *)dimm->module_part_number); - - /* Synchronous = 1 */ - t->type_detail = 0x0080; - /* no handle for error information */ - t->memory_error_information_handle = 0xFFFE; - t->attributes = dimm->rank_per_dimm; - t->handle = *handle; - *handle += 1; - t->length = sizeof(struct smbios_type17) - 2; - return t->length + smbios_string_table_len(t->eos); -} - -const char *__attribute__((weak)) smbios_mainboard_bios_version(void) -{ - if (strlen(CONFIG_LOCALVERSION)) - return CONFIG_LOCALVERSION; - else - return coreboot_version; -} - -static int smbios_write_type0(unsigned long *current, int handle) -{ - struct smbios_type0 *t = (struct smbios_type0 *)*current; - int len = sizeof(struct smbios_type0); - - memset(t, 0, sizeof(struct smbios_type0)); - t->type = SMBIOS_BIOS_INFORMATION; - t->handle = handle; - t->length = len - 2; - - t->vendor = smbios_add_string(t->eos, "coreboot"); -#if !CONFIG_CHROMEOS - t->bios_release_date = smbios_add_string(t->eos, coreboot_dmi_date); - - t->bios_version = smbios_add_string(t->eos, smbios_mainboard_bios_version()); -#else -#define SPACES \ - " " - t->bios_release_date = smbios_add_string(t->eos, coreboot_dmi_date); -#if IS_ENABLED(CONFIG_HAVE_ACPI_TABLES) - u32 version_offset = (u32)smbios_string_table_len(t->eos); -#endif - t->bios_version = smbios_add_string(t->eos, SPACES); - -#if IS_ENABLED(CONFIG_HAVE_ACPI_TABLES) - /* SMBIOS offsets start at 1 rather than 0 */ - vboot_data->vbt10 = (u32)t->eos + (version_offset - 1); -#endif -#endif /* CONFIG_CHROMEOS */ - - t->bios_rom_size = (CONFIG_ROM_SIZE / 65535) - 1; - - t->system_bios_major_release = 4; - t->bios_characteristics = - BIOS_CHARACTERISTICS_PCI_SUPPORTED | -#if CONFIG_CARDBUS_PLUGIN_SUPPORT - BIOS_CHARACTERISTICS_PC_CARD | -#endif - BIOS_CHARACTERISTICS_SELECTABLE_BOOT | - BIOS_CHARACTERISTICS_UPGRADEABLE; - -#if CONFIG_HAVE_ACPI_TABLES - t->bios_characteristics_ext1 = BIOS_EXT1_CHARACTERISTICS_ACPI; -#endif - t->bios_characteristics_ext2 = BIOS_EXT2_CHARACTERISTICS_TARGET; - len = t->length + smbios_string_table_len(t->eos); - *current += len; - return len; -} - -#if !CONFIG_SMBIOS_PROVIDED_BY_MOBO - -const char *__attribute__((weak)) smbios_mainboard_serial_number(void) -{ - return CONFIG_MAINBOARD_SERIAL_NUMBER; -} - -const char *__attribute__((weak)) smbios_mainboard_version(void) -{ - return CONFIG_MAINBOARD_VERSION; -} - -const char *__attribute__((weak)) smbios_mainboard_manufacturer(void) -{ - return CONFIG_MAINBOARD_SMBIOS_MANUFACTURER; -} - -const char *__attribute__((weak)) smbios_mainboard_product_name(void) -{ - return CONFIG_MAINBOARD_SMBIOS_PRODUCT_NAME; -} - -void __attribute__((weak)) smbios_mainboard_set_uuid(u8 *uuid) -{ - /* leave all zero */ -} -#endif - -#ifdef CONFIG_MAINBOARD_FAMILY -const char *smbios_mainboard_family(void) -{ - return CONFIG_MAINBOARD_FAMILY; -} -#endif /* CONFIG_MAINBOARD_FAMILY */ - -static int smbios_write_type1(unsigned long *current, int handle) -{ - struct smbios_type1 *t = (struct smbios_type1 *)*current; - int len = sizeof(struct smbios_type1); - - memset(t, 0, sizeof(struct smbios_type1)); - t->type = SMBIOS_SYSTEM_INFORMATION; - t->handle = handle; - t->length = len - 2; - t->manufacturer = smbios_add_string(t->eos, smbios_mainboard_manufacturer()); - t->product_name = smbios_add_string(t->eos, smbios_mainboard_product_name()); - t->serial_number = smbios_add_string(t->eos, smbios_mainboard_serial_number()); - t->version = smbios_add_string(t->eos, smbios_mainboard_version()); -#ifdef CONFIG_MAINBOARD_FAMILY - t->family = smbios_add_string(t->eos, smbios_mainboard_family()); -#endif - smbios_mainboard_set_uuid(t->uuid); - len = t->length + smbios_string_table_len(t->eos); - *current += len; - return len; -} - -static int smbios_write_type2(unsigned long *current, int handle) -{ - struct smbios_type2 *t = (struct smbios_type2 *)*current; - int len = sizeof(struct smbios_type2); - - memset(t, 0, sizeof(struct smbios_type2)); - t->type = SMBIOS_BOARD_INFORMATION; - t->handle = handle; - t->length = len - 2; - t->manufacturer = smbios_add_string(t->eos, smbios_mainboard_manufacturer()); - t->product_name = smbios_add_string(t->eos, smbios_mainboard_product_name()); - t->serial_number = smbios_add_string(t->eos, smbios_mainboard_serial_number()); - t->version = smbios_add_string(t->eos, smbios_mainboard_version()); - len = t->length + smbios_string_table_len(t->eos); - *current += len; - return len; -} - -static int smbios_write_type3(unsigned long *current, int handle) -{ - struct smbios_type3 *t = (struct smbios_type3 *)*current; - int len = sizeof(struct smbios_type3); - - memset(t, 0, sizeof(struct smbios_type3)); - t->type = SMBIOS_SYSTEM_ENCLOSURE; - t->handle = handle; - t->length = len - 2; - t->manufacturer = smbios_add_string(t->eos, smbios_mainboard_manufacturer()); - t->bootup_state = SMBIOS_STATE_SAFE; - t->power_supply_state = SMBIOS_STATE_SAFE; - t->thermal_state = SMBIOS_STATE_SAFE; - if(IS_ENABLED(CONFIG_SYSTEM_TYPE_LAPTOP)) { - t->_type = SMBIOS_ENCLOSURE_NOTEBOOK; - } else { - t->_type = SMBIOS_ENCLOSURE_DESKTOP; - } - t->security_status = SMBIOS_STATE_SAFE; - len = t->length + smbios_string_table_len(t->eos); - *current += len; - return len; -} - -static int smbios_write_type4(unsigned long *current, int handle) -{ - struct cpuid_result res; - struct smbios_type4 *t = (struct smbios_type4 *)*current; - int len = sizeof(struct smbios_type4); - - /* Provide sane defaults even for CPU without CPUID */ - res.eax = res.edx = 0; - res.ebx = 0x10000; - - if (cpu_have_cpuid()) { - res = cpuid(1); - } - - memset(t, 0, sizeof(struct smbios_type4)); - t->type = SMBIOS_PROCESSOR_INFORMATION; - t->handle = handle; - t->length = len - 2; - t->processor_id[0] = res.eax; - t->processor_id[1] = res.edx; - t->processor_manufacturer = smbios_cpu_vendor(t->eos); - t->processor_version = smbios_processor_name(t->eos); - t->processor_family = (res.eax > 0) ? 0x0c : 0x6; - t->processor_type = 3; /* System Processor */ - t->processor_upgrade = 0x06; - t->core_count = (res.ebx >> 16) & 0xff; - t->l1_cache_handle = 0xffff; - t->l2_cache_handle = 0xffff; - t->l3_cache_handle = 0xffff; - t->processor_upgrade = 1; - len = t->length + smbios_string_table_len(t->eos); - *current += len; - return len; -} - -static int smbios_write_type11(unsigned long *current, int *handle) -{ - struct smbios_type11 *t = (struct smbios_type11 *)*current; - int len; - struct device *dev; - - memset(t, 0, sizeof *t); - t->type = SMBIOS_OEM_STRINGS; - t->handle = *handle; - t->length = len = sizeof *t - 2; - - for(dev = all_devices; dev; dev = dev->next) { - if (dev->ops && dev->ops->get_smbios_strings) - dev->ops->get_smbios_strings(dev, t); - } - - if (t->count == 0) { - memset(t, 0, sizeof *t); - return 0; - } - - len += smbios_string_table_len(t->eos); - - *current += len; - (*handle)++; - return len; -} - -static int smbios_write_type17(unsigned long *current, int *handle) -{ - int len = sizeof(struct smbios_type17); - int i; - - struct memory_info *meminfo; - meminfo = cbmem_find(CBMEM_ID_MEMINFO); - if (meminfo == NULL) - return 0; /* can't find mem info in cbmem */ - - printk(BIOS_INFO, "Create SMBIOS type 17\n"); - for (i = 0; i < meminfo->dimm_cnt && i < ARRAY_SIZE(meminfo->dimm); i++) { - struct dimm_info *dimm; - dimm = &meminfo->dimm[i]; - len = create_smbios_type17_for_dimm(dimm, current, handle); - *current += len; - } - return meminfo->dimm_cnt * len; -} - -static int smbios_write_type32(unsigned long *current, int handle) -{ - struct smbios_type32 *t = (struct smbios_type32 *)*current; - int len = sizeof(struct smbios_type32); - - memset(t, 0, sizeof(struct smbios_type32)); - t->type = SMBIOS_SYSTEM_BOOT_INFORMATION; - t->handle = handle; - t->length = len - 2; - *current += len; - return len; -} - -int smbios_write_type41(unsigned long *current, int *handle, - const char *name, u8 instance, u16 segment, - u8 bus, u8 device, u8 function) -{ - struct smbios_type41 *t = (struct smbios_type41 *)*current; - int len = sizeof(struct smbios_type41); - - memset(t, 0, sizeof(struct smbios_type41)); - t->type = SMBIOS_ONBOARD_DEVICES_EXTENDED_INFORMATION; - t->handle = *handle; - t->length = len - 2; - t->reference_designation = smbios_add_string(t->eos, name); - t->device_type = SMBIOS_DEVICE_TYPE_OTHER; - t->device_status = 1; - t->device_type_instance = instance; - t->segment_group_number = segment; - t->bus_number = bus; - t->device_number = device; - t->function_number = function; - - len = t->length + smbios_string_table_len(t->eos); - *current += len; - *handle += 1; - return len; -} - -static int smbios_write_type127(unsigned long *current, int handle) -{ - struct smbios_type127 *t = (struct smbios_type127 *)*current; - int len = sizeof(struct smbios_type127); - - memset(t, 0, sizeof(struct smbios_type127)); - t->type = SMBIOS_END_OF_TABLE; - t->handle = handle; - t->length = len - 2; - *current += len; - return len; -} - -static int smbios_walk_device_tree(struct device *tree, int *handle, unsigned long *current) -{ - struct device *dev; - int len = 0; - - for(dev = tree; dev; dev = dev->next) { - printk(BIOS_INFO, "%s (%s)\n", dev_path(dev), dev_name(dev)); - - if (dev->ops && dev->ops->get_smbios_data) - len += dev->ops->get_smbios_data(dev, handle, current); - } - return len; -} - -#define update_max(len, max_len, stmt) do { int tmp = stmt; max_len = MAX(max_len, tmp); len += tmp; } while(0) -unsigned long smbios_write_tables(unsigned long current) -{ - struct smbios_entry *se; - unsigned long tables; - int len = 0; - int max_struct_size = 0; - int handle = 0; - - current = ALIGN(current, 16); - printk(BIOS_DEBUG, "%s: %08lx\n", __func__, current); - - se = (struct smbios_entry *)current; - current += sizeof(struct smbios_entry); - current = ALIGN(current, 16); - - tables = current; - update_max(len, max_struct_size, smbios_write_type0(¤t, handle++)); - update_max(len, max_struct_size, smbios_write_type1(¤t, handle++)); - update_max(len, max_struct_size, smbios_write_type2(¤t, handle++)); - update_max(len, max_struct_size, smbios_write_type3(¤t, handle++)); - update_max(len, max_struct_size, smbios_write_type4(¤t, handle++)); - update_max(len, max_struct_size, smbios_write_type11(¤t, &handle)); -#if CONFIG_ELOG - update_max(len, max_struct_size, elog_smbios_write_type15(¤t, handle++)); -#endif - update_max(len, max_struct_size, smbios_write_type17(¤t, &handle)); - update_max(len, max_struct_size, smbios_write_type32(¤t, handle++)); - - update_max(len, max_struct_size, smbios_walk_device_tree(all_devices, &handle, ¤t)); - - update_max(len, max_struct_size, smbios_write_type127(¤t, handle++)); - - memset(se, 0, sizeof(struct smbios_entry)); - memcpy(se->anchor, "_SM_", 4); - se->length = sizeof(struct smbios_entry); - se->major_version = 2; - se->minor_version = 7; - se->max_struct_size = max_struct_size; - se->struct_count = handle; - memcpy(se->intermediate_anchor_string, "_DMI_", 5); - - se->struct_table_address = (u32)tables; - se->struct_table_length = len; - - se->intermediate_checksum = smbios_checksum((u8 *)se + 0x10, - sizeof(struct smbios_entry) - 0x10); - se->checksum = smbios_checksum((u8 *)se, sizeof(struct smbios_entry)); - return current; -} diff --git a/src/arch/x86/boot/tables.c b/src/arch/x86/boot/tables.c deleted file mode 100644 index 3d645633f0..0000000000 --- a/src/arch/x86/boot/tables.c +++ /dev/null @@ -1,221 +0,0 @@ -/* - * This file is part of the coreboot project. - * - * Copyright (C) 2003 Eric Biederman - * Copyright (C) 2005 Steve Magnani - * Copyright (C) 2008-2009 coresystems GmbH - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; version 2 of the License. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc. - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -void write_tables(void) -{ - unsigned long low_table_start, low_table_end; - unsigned long rom_table_start, rom_table_end; - - /* Even if high tables are configured, some tables are copied both to - * the low and the high area, so payloads and OSes don't need to know - * about the high tables. - */ - unsigned long high_table_pointer; - - rom_table_start = 0xf0000; - rom_table_end = 0xf0000; - - /* Start low addr at 0x500, so we don't run into conflicts with the BDA - * in case our data structures grow beyond 0x400. Only GDT - * and the coreboot table use low_tables. - */ - low_table_start = 0; - low_table_end = 0x500; - -#if CONFIG_GENERATE_PIRQ_TABLE -#define MAX_PIRQ_TABLE_SIZE (4 * 1024) - post_code(0x9a); - - /* This table must be between 0x0f0000 and 0x100000 */ - rom_table_end = write_pirq_routing_table(rom_table_end); - rom_table_end = ALIGN(rom_table_end, 1024); - - /* And add a high table version for those payloads that - * want to live in the F segment - */ - high_table_pointer = (unsigned long)cbmem_add(CBMEM_ID_PIRQ, MAX_PIRQ_TABLE_SIZE); - if (high_table_pointer) { - unsigned long new_high_table_pointer; - new_high_table_pointer = write_pirq_routing_table(high_table_pointer); - // FIXME make pirq table code intelligent enough to know how - // much space it's going to need. - if (new_high_table_pointer > (high_table_pointer + MAX_PIRQ_TABLE_SIZE)) { - printk(BIOS_ERR, "ERROR: Increase PIRQ size.\n"); - } - printk(BIOS_DEBUG, "PIRQ table: %ld bytes.\n", - new_high_table_pointer - high_table_pointer); - } - -#endif - -#if CONFIG_GENERATE_MP_TABLE -#define MAX_MP_TABLE_SIZE (4 * 1024) - post_code(0x9b); - - /* The smp table must be in 0-1K, 639K-640K, or 960K-1M */ - rom_table_end = write_smp_table(rom_table_end); - rom_table_end = ALIGN(rom_table_end, 1024); - - high_table_pointer = (unsigned long)cbmem_add(CBMEM_ID_MPTABLE, MAX_MP_TABLE_SIZE); - if (high_table_pointer) { - unsigned long new_high_table_pointer; - new_high_table_pointer = write_smp_table(high_table_pointer); - // FIXME make mp table code intelligent enough to know how - // much space it's going to need. - if (new_high_table_pointer > (high_table_pointer + MAX_MP_TABLE_SIZE)) { - printk(BIOS_ERR, "ERROR: Increase MP table size.\n"); - } - - printk(BIOS_DEBUG, "MP table: %ld bytes.\n", - new_high_table_pointer - high_table_pointer); - } -#endif /* CONFIG_GENERATE_MP_TABLE */ - -#if CONFIG_HAVE_ACPI_TABLES -#define MAX_ACPI_SIZE (144 * 1024) - - post_code(0x9c); - - /* Write ACPI tables to F segment and high tables area */ - - /* Ok, this is a bit hacky still, because some day we want to have this - * completely dynamic. But right now we are setting fixed sizes. - * It's probably still better than the old high_table_base code because - * now at least we know when we have an overflow in the area. - * - * We want to use 1MB - 64K for Resume backup. We use 512B for TOC and - * 512 byte for GDT, 4K for PIRQ and 4K for MP table and 8KB for the - * coreboot table. This leaves us with 47KB for all of ACPI. Let's see - * how far we get. - */ - high_table_pointer = (unsigned long)cbmem_add(CBMEM_ID_ACPI, MAX_ACPI_SIZE); - if (high_table_pointer) { - unsigned long acpi_start = high_table_pointer; - unsigned long new_high_table_pointer; - - rom_table_end = ALIGN(rom_table_end, 16); - new_high_table_pointer = write_acpi_tables(high_table_pointer); - if (new_high_table_pointer > ( high_table_pointer + MAX_ACPI_SIZE)) { - printk(BIOS_ERR, "ERROR: Increase ACPI size\n"); - } - printk(BIOS_DEBUG, "ACPI tables: %ld bytes.\n", - new_high_table_pointer - high_table_pointer); - - /* Now we need to create a low table copy of the RSDP. */ - - /* First we look for the high table RSDP */ - while (acpi_start < new_high_table_pointer) { - if (memcmp(((acpi_rsdp_t *)acpi_start)->signature, RSDP_SIG, 8) == 0) { - break; - } - acpi_start++; - } - - /* Now, if we found the RSDP, we take the RSDT and XSDT pointer - * from it in order to write the low RSDP - */ - if (acpi_start < new_high_table_pointer) { - acpi_rsdp_t *low_rsdp = (acpi_rsdp_t *)rom_table_end, - *high_rsdp = (acpi_rsdp_t *)acpi_start; - - /* Technically rsdp length varies but coreboot always - writes longest size available. */ - memcpy(low_rsdp, high_rsdp, sizeof(acpi_rsdp_t)); - } else { - printk(BIOS_ERR, "ERROR: Didn't find RSDP in high table.\n"); - } - rom_table_end = ALIGN(rom_table_end + sizeof(acpi_rsdp_t), 16); - } else { - rom_table_end = write_acpi_tables(rom_table_end); - rom_table_end = ALIGN(rom_table_end, 1024); - } - -#endif -#define MAX_SMBIOS_SIZE 2048 -#if CONFIG_GENERATE_SMBIOS_TABLES - high_table_pointer = (unsigned long)cbmem_add(CBMEM_ID_SMBIOS, MAX_SMBIOS_SIZE); - if (high_table_pointer) { - unsigned long new_high_table_pointer; - - new_high_table_pointer = smbios_write_tables(high_table_pointer); - rom_table_end = ALIGN(rom_table_end, 16); - memcpy((void *)rom_table_end, (void *)high_table_pointer, sizeof(struct smbios_entry)); - rom_table_end += sizeof(struct smbios_entry); - - if (new_high_table_pointer > ( high_table_pointer + MAX_SMBIOS_SIZE)) { - printk(BIOS_ERR, "ERROR: Increase SMBIOS size\n"); - } - printk(BIOS_DEBUG, "SMBIOS tables: %ld bytes.\n", - new_high_table_pointer - high_table_pointer); - } else { - unsigned long new_rom_table_end = smbios_write_tables(rom_table_end); - printk(BIOS_DEBUG, "SMBIOS size %ld bytes\n", new_rom_table_end - rom_table_end); - rom_table_end = ALIGN(new_rom_table_end, 16); - } -#endif - - post_code(0x9e); - -#define MAX_COREBOOT_TABLE_SIZE (32 * 1024) - post_code(0x9d); - - high_table_pointer = (unsigned long)cbmem_add(CBMEM_ID_CBTABLE, MAX_COREBOOT_TABLE_SIZE); - - if (high_table_pointer) { - unsigned long new_high_table_pointer; - - /* FIXME: The high_table_base parameter is not reference when tables are high, - * or high_table_pointer >1 MB. - */ - u64 fixme_high_tables_base = 0; - - /* Also put a forwarder entry into 0-4K */ - new_high_table_pointer = write_coreboot_table(low_table_start, low_table_end, - fixme_high_tables_base, high_table_pointer); - - if (new_high_table_pointer > (high_table_pointer + - MAX_COREBOOT_TABLE_SIZE)) - printk(BIOS_ERR, "%s: coreboot table didn't fit (%lx)\n", - __func__, new_high_table_pointer - - high_table_pointer); - - printk(BIOS_DEBUG, "coreboot table: %ld bytes.\n", - new_high_table_pointer - high_table_pointer); - } else { - /* The coreboot table must be in 0-4K or 960K-1M */ - write_coreboot_table(low_table_start, low_table_end, - rom_table_start, rom_table_end); - } - - /* Print CBMEM sections */ - cbmem_list(); -} diff --git a/src/arch/x86/boot/wakeup.S b/src/arch/x86/boot/wakeup.S deleted file mode 100644 index 38d6ea43ae..0000000000 --- a/src/arch/x86/boot/wakeup.S +++ /dev/null @@ -1,99 +0,0 @@ -/* - * This file is part of the coreboot project. - * - * Copyright (C) 2009 Rudolf Marek - * Copyright (C) 2009 coresystems GmbH - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; version 2 of the License. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc. - */ - -#define WAKEUP_BASE 0x600 -#define RELOCATED(x) (x - __wakeup + WAKEUP_BASE) - -/* CR0 bits */ -#define PE (1 << 0) - -#ifdef __x86_64__ - .code64 -#else - .code32 -#endif - - .globl __wakeup -__wakeup: - /* First prepare the jmp to the resume vector */ - mov 0x4(%esp), %eax /* vector */ - /* last 4 bits of linear addr are taken as offset */ - andw $0x0f, %ax - movw %ax, (__wakeup_offset) - mov 0x4(%esp), %eax - /* the rest is taken as segment */ - shr $4, %eax - movw %ax, (__wakeup_segment) - - /* Then overwrite coreboot with our backed up memory */ - cld - movl 8(%esp), %esi - movl 12(%esp), %edi - movl 16(%esp), %ecx - shrl $2, %ecx - rep movsl - - /* Activate the right segment descriptor real mode. */ - ljmp $0x28, $RELOCATED(1f) -1: -.code16 - /* 16 bit code from here on... */ - - /* Load the segment registers w/ properly configured - * segment descriptors. They will retain these - * configurations (limits, writability, etc.) once - * protected mode is turned off. - */ - mov $0x30, %ax - mov %ax, %ds - mov %ax, %es - mov %ax, %fs - mov %ax, %gs - mov %ax, %ss - - /* Turn off protection */ - movl %cr0, %eax - andl $~PE, %eax - movl %eax, %cr0 - - /* Now really going into real mode */ - ljmp $0, $RELOCATED(1f) -1: - movw $0x0, %ax - movw %ax, %ds - movw %ax, %es - movw %ax, %ss - movw %ax, %fs - movw %ax, %gs - - /* This is a FAR JMP to the OS waking vector. The C code changed - * the address to be correct. - */ - .byte 0xea - -__wakeup_offset = RELOCATED(.) - .word 0x0000 - -__wakeup_segment = RELOCATED(.) - .word 0x0000 - - .globl __wakeup_size -__wakeup_size: - .long . - __wakeup diff --git a/src/arch/x86/bootblock_normal.c b/src/arch/x86/bootblock_normal.c new file mode 100644 index 0000000000..bde2535ba6 --- /dev/null +++ b/src/arch/x86/bootblock_normal.c @@ -0,0 +1,52 @@ +#include +#include +#include +#include + +static const char *get_fallback(const char *stagelist) { + while (*stagelist) stagelist++; + return ++stagelist; +} + +static void main(unsigned long bist) +{ + unsigned long entry; + int boot_mode; + const char *default_filenames = "normal/romstage\0fallback/romstage"; + + if (boot_cpu()) { + bootblock_mainboard_init(); + +#if CONFIG_USE_OPTION_TABLE + sanitize_cmos(); +#endif + boot_mode = do_normal_boot(); + } else { + + /* Questionable single byte read from CMOS. + * Do not add any other CMOS access in the + * bootblock for AP CPUs. + */ + boot_mode = last_boot_normal(); + } + + char *filenames = (char *)walkcbfs("coreboot-stages"); + if (!filenames) { + filenames = default_filenames; + } + char *normal_candidate = filenames; + + if (boot_mode) + entry = findstage(normal_candidate); + else + entry = findstage(get_fallback(normal_candidate)); + + if (entry) call(entry, bist); + + /* run fallback if normal can't be found */ + entry = findstage(get_fallback(normal_candidate)); + if (entry) call(entry, bist); + + /* duh. we're stuck */ + halt(); +} diff --git a/src/arch/x86/bootblock_simple.c b/src/arch/x86/bootblock_simple.c new file mode 100644 index 0000000000..adeecf7ba6 --- /dev/null +++ b/src/arch/x86/bootblock_simple.c @@ -0,0 +1,23 @@ +#include +#include +#include + +static void main(unsigned long bist) +{ + if (boot_cpu()) { + bootblock_mainboard_init(); + +#if CONFIG_USE_OPTION_TABLE + sanitize_cmos(); +#endif +#if CONFIG_CMOS_POST + cmos_post_init(); +#endif + } + + const char* target1 = "fallback/romstage"; + unsigned long entry; + entry = findstage(target1); + if (entry) call(entry, bist); + halt(); +} diff --git a/src/arch/x86/c_start.S b/src/arch/x86/c_start.S new file mode 100644 index 0000000000..582966bfdc --- /dev/null +++ b/src/arch/x86/c_start.S @@ -0,0 +1,421 @@ +#include + +/* Place the stack in the bss section. It's not necessary to define it in the + * the linker script. */ + .section .bss, "aw", @nobits +.global _stack +.global _estack + +.align CONFIG_STACK_SIZE +_stack: +.space CONFIG_MAX_CPUS*CONFIG_STACK_SIZE +_estack: +#if CONFIG_COOP_MULTITASKING +.global thread_stacks +thread_stacks: +.space CONFIG_STACK_SIZE*CONFIG_NUM_THREADS +#endif + + .section ".text._start", "ax", @progbits +#ifdef __x86_64__ + .code64 +#else + .code32 +#endif + .globl _start + .globl __rmodule_entry +__rmodule_entry: +_start: + cli + lgdt %cs:gdtaddr +#ifndef __x86_64__ + ljmp $0x10, $1f +#endif +1: movl $0x18, %eax + movl %eax, %ds + movl %eax, %es + movl %eax, %ss + movl %eax, %fs + movl %eax, %gs +#ifdef __x86_64__ + mov $0x48, %ecx + call SetCodeSelector +#endif + + post_code(POST_ENTRY_C_START) /* post 13 */ + + cld + + /** poison the stack. Code should not count on the + * stack being full of zeros. This stack poisoning + * recently uncovered a bug in the broadcast SIPI + * code. + */ + leal _stack, %edi + movl $_estack, %ecx + subl %edi, %ecx + shrl $2, %ecx /* it is 32 bit aligned, right? */ + movl $0xDEADBEEF, %eax + rep + stosl + + /* set new stack */ + movl $_estack, %esp + +#if CONFIG_COOP_MULTITASKING + /* Push the thread pointer. */ + push $0 +#endif + /* Push the cpu index and struct cpu */ + push $0 + push $0 + + /* Initialize the Interrupt Descriptor table */ + leal _idt, %edi + leal vec0, %ebx + movl $(0x10 << 16), %eax /* cs selector */ + +1: movw %bx, %ax + movl %ebx, %edx + movw $0x8E00, %dx /* Interrupt gate - dpl=0, present */ + movl %eax, 0(%edi) + movl %edx, 4(%edi) + addl $6, %ebx + addl $8, %edi + cmpl $_idt_end, %edi + jne 1b + + /* Load the Interrupt descriptor table */ +#ifndef __x86_64__ + lidt idtarg +#else + // FIXME port table to x64 - lidt idtarg +#endif + + /* + * Now we are finished. Memory is up, data is copied and + * bss is cleared. Now we call the main routine and + * let it do the rest. + */ + post_code(POST_PRE_HARDWAREMAIN) /* post fe */ + +#if CONFIG_GDB_WAIT + call gdb_hw_init + call gdb_stub_breakpoint +#endif + call main + /* NOTREACHED */ +.Lhlt: + post_code(POST_DEAD_CODE) /* post ee */ + hlt + jmp .Lhlt + +vec0: + push $0 /* error code */ + push $0 /* vector */ + jmp int_hand +vec1: + push $0 /* error code */ + push $1 /* vector */ + jmp int_hand + +vec2: + push $0 /* error code */ + push $2 /* vector */ + jmp int_hand + +vec3: + push $0 /* error code */ + push $3 /* vector */ + jmp int_hand + +vec4: + push $0 /* error code */ + push $4 /* vector */ + jmp int_hand + +vec5: + push $0 /* error code */ + push $5 /* vector */ + jmp int_hand + +vec6: + push $0 /* error code */ + push $6 /* vector */ + jmp int_hand + +vec7: + push $0 /* error code */ + push $7 /* vector */ + jmp int_hand + +vec8: + /* error code */ + push $8 /* vector */ + jmp int_hand + .word 0x9090 + +vec9: + push $0 /* error code */ + push $9 /* vector */ + jmp int_hand + +vec10: + /* error code */ + push $10 /* vector */ + jmp int_hand + .word 0x9090 + +vec11: + /* error code */ + push $11 /* vector */ + jmp int_hand + .word 0x9090 + +vec12: + /* error code */ + push $12 /* vector */ + jmp int_hand + .word 0x9090 + +vec13: + /* error code */ + push $13 /* vector */ + jmp int_hand + .word 0x9090 + +vec14: + /* error code */ + push $14 /* vector */ + jmp int_hand + .word 0x9090 + +vec15: + push $0 /* error code */ + push $15 /* vector */ + jmp int_hand + +vec16: + push $0 /* error code */ + push $16 /* vector */ + jmp int_hand + +vec17: + /* error code */ + push $17 /* vector */ + jmp int_hand + .word 0x9090 + +vec18: + push $0 /* error code */ + push $18 /* vector */ + jmp int_hand + +vec19: + push $0 /* error code */ + push $19 /* vector */ + jmp int_hand + +int_hand: + /* At this point, on x86-32, on the stack there is: + * 0(%esp) vector + * 4(%esp) error code + * 8(%esp) eip + * 12(%esp) cs + * 16(%esp) eflags + */ +#ifdef __x86_64__ + push %rdi + push %rsi + push %rbp + /* Original stack pointer */ + lea 32(%rsp), %rbp + push %rbp + push %rbx + push %rdx + push %rcx + push %rax + + push %rsp /* Pointer to structure on the stack */ + call x86_exception + pop %rax /* Drop the pointer */ + + pop %rax + pop %rcx + pop %rdx + pop %rbx + pop %rbp /* Ignore saved %rsp value */ + pop %rbp + pop %rsi + pop %rdi + + add $8, %rsp /* pop of the vector and error code */ +#else + pushl %edi + pushl %esi + pushl %ebp + + /* Original stack pointer */ + leal 32(%esp), %ebp + pushl %ebp + pushl %ebx + pushl %edx + pushl %ecx + pushl %eax + + pushl %esp /* Pointer to structure on the stack */ + call x86_exception + pop %eax /* Drop the pointer */ + + popl %eax + popl %ecx + popl %edx + popl %ebx + popl %ebp /* Ignore saved %esp value */ + popl %ebp + popl %esi + popl %edi + + addl $8, %esp /* pop of the vector and error code */ +#endif + + iret + +#if CONFIG_GDB_WAIT + + .globl gdb_stub_breakpoint +gdb_stub_breakpoint: +#ifdef __x86_64__ + pop %rax /* Return address */ + pushfl + push %cs + push %rax /* Return address */ + push $0 /* No error code */ + push $32 /* vector 32 is user defined */ +#else + popl %eax /* Return address */ + pushfl + pushl %cs + pushl %eax /* Return address */ + pushl $0 /* No error code */ + pushl $32 /* vector 32 is user defined */ +#endif + jmp int_hand +#endif + + .globl gdt, gdt_end, idtarg + +gdtaddr: + .word gdt_end - gdt - 1 +#ifdef __x86_64__ + .quad gdt +#else + .long gdt /* we know the offset */ +#endif + + .data + + /* This is the gdt for GCC part of coreboot. + * It is different from the gdt in ROMCC/ASM part of coreboot + * which is defined in entry32.inc + * + * When the machine is initially started, we use a very simple + * gdt from rom (that in entry32.inc) which only contains those + * entries we need for protected mode. + * + * When we're executing code from RAM, we want to do more complex + * stuff, like initializing PCI option roms in real mode, or doing + * a resume from a suspend to ram. + */ +gdt: + /* selgdt 0, unused */ + .word 0x0000, 0x0000 /* dummy */ + .byte 0x00, 0x00, 0x00, 0x00 + + /* selgdt 8, unused */ + .word 0x0000, 0x0000 /* dummy */ + .byte 0x00, 0x00, 0x00, 0x00 + + /* selgdt 0x10, flat code segment */ + .word 0xffff, 0x0000 + .byte 0x00, 0x9b, 0xcf, 0x00 /* G=1 and 0x0f, So we get 4Gbytes for limit */ + + /* selgdt 0x18, flat data segment */ + .word 0xffff, 0x0000 +#ifdef __x86_64__ + .byte 0x00, 0x92, 0xcf, 0x00 +#else + .byte 0x00, 0x93, 0xcf, 0x00 +#endif + + /* selgdt 0x20, unused */ + .word 0x0000, 0x0000 /* dummy */ + .byte 0x00, 0x00, 0x00, 0x00 + + /* The next two entries are used for executing VGA option ROMs */ + + /* selgdt 0x28 16 bit 64k code at 0x00000000 */ + .word 0xffff, 0x0000 + .byte 0, 0x9a, 0, 0 + + /* selgdt 0x30 16 bit 64k data at 0x00000000 */ + .word 0xffff, 0x0000 + .byte 0, 0x92, 0, 0 + + /* The next two entries are used for ACPI S3 RESUME */ + + /* selgdt 0x38, flat data segment 16 bit */ + .word 0x0000, 0x0000 /* dummy */ + .byte 0x00, 0x93, 0x8f, 0x00 /* G=1 and 0x0f, So we get 4Gbytes for limit */ + + /* selgdt 0x40, flat code segment 16 bit */ + .word 0xffff, 0x0000 + .byte 0x00, 0x9b, 0x8f, 0x00 /* G=1 and 0x0f, So we get 4Gbytes for limit */ + +#ifdef __x86_64__ + /* selgdt 0x48, flat x64 code segment */ + .word 0xffff, 0x0000 + .byte 0x00, 0x9b, 0xaf, 0x00 +#endif +gdt_end: + +idtarg: + .word _idt_end - _idt - 1 /* limit */ + .long _idt + .word 0 +_idt: + .fill 20, 8, 0 # idt is uninitialized +_idt_end: + +#ifdef __x86_64__ +SetCodeSelector: +.intel_syntax noprefix + + # save rsp because iret will align it to a 16 byte boundary + mov rdx, rsp + + # use iret to jump to a 64-bit offset in a new code segment + # iret will pop cs:rip, flags, then ss:rsp + mov ax, ss # need to push ss.. + push rax # push ss instuction not valid in x64 mode, so use ax + push rsp + pushfq + push rcx # cx is code segment selector from caller + mov rax, offset setCodeSelectorLongJump + push rax + + # the iret will continue at next instruction, with the new cs value loaded + iretq + +setCodeSelectorLongJump: + # restore rsp, it might not have been 16-byte aligned on entry + mov rsp, rdx + ret +.att_syntax prefix + + .previous +.code64 +#else + .previous +.code32 +#endif diff --git a/src/arch/x86/cbfs_and_run.c b/src/arch/x86/cbfs_and_run.c new file mode 100644 index 0000000000..b6d342623d --- /dev/null +++ b/src/arch/x86/cbfs_and_run.c @@ -0,0 +1,26 @@ +/* + * This file is part of the coreboot project. + * + * Copyright (C) 2008-2009 coresystems GmbH + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; version 2 of the License. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc. + */ + +#include +#include + +void asmlinkage copy_and_run(void) +{ + run_ramstage(); +} diff --git a/src/arch/x86/cbmem.c b/src/arch/x86/cbmem.c new file mode 100644 index 0000000000..e279db960c --- /dev/null +++ b/src/arch/x86/cbmem.c @@ -0,0 +1,76 @@ +/* + * This file is part of the coreboot project. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; version 2 of the License. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc. + */ + +#include +#include +#include +#include + +#if IS_ENABLED(CONFIG_LATE_CBMEM_INIT) + +#if !defined(__PRE_RAM__) +void __attribute__((weak)) backup_top_of_ram(uint64_t ramtop) +{ + /* Do nothing. Chipset may have implementation to save ramtop in NVRAM. */ +} + +static void *ramtop_pointer; + +void set_top_of_ram(uint64_t ramtop) +{ + backup_top_of_ram(ramtop); + ramtop_pointer = (void *)(uintptr_t)ramtop; +} + +static inline void *saved_ramtop(void) +{ + return ramtop_pointer; +} +#else +static inline void *saved_ramtop(void) +{ + return NULL; +} +#endif /* !__PRE_RAM__ */ + +unsigned long __attribute__((weak)) get_top_of_ram(void) +{ + return 0; +} + +void *cbmem_top(void) +{ + /* Top of cbmem is at lowest usable DRAM address below 4GiB. */ + void *ptr = saved_ramtop(); + + if (ptr != NULL) + return ptr; + + return (void *)get_top_of_ram(); +} + +#endif /* LATE_CBMEM_INIT */ + +/* Something went wrong, our high memory area got wiped */ +void cbmem_fail_resume(void) +{ +#if !defined(__PRE_RAM__) && IS_ENABLED(CONFIG_HAVE_ACPI_RESUME) + /* ACPI resume needs to be cleared in the fail-to-recover case, but that + * condition is only handled during ramstage. */ + acpi_fail_wakeup(); +#endif +} diff --git a/src/arch/x86/cpu.c b/src/arch/x86/cpu.c new file mode 100644 index 0000000000..3eb7b9439e --- /dev/null +++ b/src/arch/x86/cpu.c @@ -0,0 +1,273 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#ifndef __x86_64__ +/* Standard macro to see if a specific flag is changeable */ +static inline int flag_is_changeable_p(uint32_t flag) +{ + uint32_t f1, f2; + + asm( + "pushfl\n\t" + "pushfl\n\t" + "popl %0\n\t" + "movl %0,%1\n\t" + "xorl %2,%0\n\t" + "pushl %0\n\t" + "popfl\n\t" + "pushfl\n\t" + "popl %0\n\t" + "popfl\n\t" + : "=&r" (f1), "=&r" (f2) + : "ir" (flag)); + return ((f1^f2) & flag) != 0; +} + +/* + * Cyrix CPUs without cpuid or with cpuid not yet enabled can be detected + * by the fact that they preserve the flags across the division of 5/2. + * PII and PPro exhibit this behavior too, but they have cpuid available. + */ + +/* + * Perform the Cyrix 5/2 test. A Cyrix won't change + * the flags, while other 486 chips will. + */ +static inline int test_cyrix_52div(void) +{ + unsigned int test; + + __asm__ __volatile__( + "sahf\n\t" /* clear flags (%eax = 0x0005) */ + "div %b2\n\t" /* divide 5 by 2 */ + "lahf" /* store flags into %ah */ + : "=a" (test) + : "0" (5), "q" (2) + : "cc"); + + /* AH is 0x02 on Cyrix after the divide.. */ + return (unsigned char) (test >> 8) == 0x02; +} + +/* + * Detect a NexGen CPU running without BIOS hypercode new enough + * to have CPUID. (Thanks to Herbert Oppmann) + */ + +static int deep_magic_nexgen_probe(void) +{ + int ret; + + __asm__ __volatile__ ( + " movw $0x5555, %%ax\n" + " xorw %%dx,%%dx\n" + " movw $2, %%cx\n" + " divw %%cx\n" + " movl $0, %%eax\n" + " jnz 1f\n" + " movl $1, %%eax\n" + "1:\n" + : "=a" (ret) : : "cx", "dx" ); + return ret; +} +#endif + +/* List of cpu vendor strings along with their normalized + * id values. + */ +static struct { + int vendor; + const char *name; +} x86_vendors[] = { + { X86_VENDOR_INTEL, "GenuineIntel", }, + { X86_VENDOR_CYRIX, "CyrixInstead", }, + { X86_VENDOR_AMD, "AuthenticAMD", }, + { X86_VENDOR_UMC, "UMC UMC UMC ", }, + { X86_VENDOR_NEXGEN, "NexGenDriven", }, + { X86_VENDOR_CENTAUR, "CentaurHauls", }, + { X86_VENDOR_RISE, "RiseRiseRise", }, + { X86_VENDOR_TRANSMETA, "GenuineTMx86", }, + { X86_VENDOR_TRANSMETA, "TransmetaCPU", }, + { X86_VENDOR_NSC, "Geode by NSC", }, + { X86_VENDOR_SIS, "SiS SiS SiS ", }, +}; + +static const char *x86_vendor_name[] = { + [X86_VENDOR_INTEL] = "Intel", + [X86_VENDOR_CYRIX] = "Cyrix", + [X86_VENDOR_AMD] = "AMD", + [X86_VENDOR_UMC] = "UMC", + [X86_VENDOR_NEXGEN] = "NexGen", + [X86_VENDOR_CENTAUR] = "Centaur", + [X86_VENDOR_RISE] = "Rise", + [X86_VENDOR_TRANSMETA] = "Transmeta", + [X86_VENDOR_NSC] = "NSC", + [X86_VENDOR_SIS] = "SiS", +}; + +static const char *cpu_vendor_name(int vendor) +{ + const char *name; + name = ""; + if ((vendor < (ARRAY_SIZE(x86_vendor_name))) && + (x86_vendor_name[vendor] != 0)) + { + name = x86_vendor_name[vendor]; + } + return name; +} + +static void identify_cpu(struct device *cpu) +{ + char vendor_name[16]; + int i; + + vendor_name[0] = '\0'; /* Unset */ + +#ifndef __x86_64__ + /* Find the id and vendor_name */ + if (!cpu_have_cpuid()) { + /* Its a 486 if we can modify the AC flag */ + if (flag_is_changeable_p(X86_EFLAGS_AC)) { + cpu->device = 0x00000400; /* 486 */ + } else { + cpu->device = 0x00000300; /* 386 */ + } + if ((cpu->device == 0x00000400) && test_cyrix_52div()) { + memcpy(vendor_name, "CyrixInstead", 13); + /* If we ever care we can enable cpuid here */ + } + /* Detect NexGen with old hypercode */ + else if (deep_magic_nexgen_probe()) { + memcpy(vendor_name, "NexGenDriven", 13); + } + } +#endif + if (cpu_have_cpuid()) { + int cpuid_level; + struct cpuid_result result; + result = cpuid(0x00000000); + cpuid_level = result.eax; + vendor_name[ 0] = (result.ebx >> 0) & 0xff; + vendor_name[ 1] = (result.ebx >> 8) & 0xff; + vendor_name[ 2] = (result.ebx >> 16) & 0xff; + vendor_name[ 3] = (result.ebx >> 24) & 0xff; + vendor_name[ 4] = (result.edx >> 0) & 0xff; + vendor_name[ 5] = (result.edx >> 8) & 0xff; + vendor_name[ 6] = (result.edx >> 16) & 0xff; + vendor_name[ 7] = (result.edx >> 24) & 0xff; + vendor_name[ 8] = (result.ecx >> 0) & 0xff; + vendor_name[ 9] = (result.ecx >> 8) & 0xff; + vendor_name[10] = (result.ecx >> 16) & 0xff; + vendor_name[11] = (result.ecx >> 24) & 0xff; + vendor_name[12] = '\0'; + + /* Intel-defined flags: level 0x00000001 */ + if (cpuid_level >= 0x00000001) { + cpu->device = cpuid_eax(0x00000001); + } + else { + /* Have CPUID level 0 only unheard of */ + cpu->device = 0x00000400; + } + } + cpu->vendor = X86_VENDOR_UNKNOWN; + for(i = 0; i < ARRAY_SIZE(x86_vendors); i++) { + if (memcmp(vendor_name, x86_vendors[i].name, 12) == 0) { + cpu->vendor = x86_vendors[i].vendor; + break; + } + } +} + +struct cpu_driver *find_cpu_driver(struct device *cpu) +{ + struct cpu_driver *driver; + for (driver = cpu_drivers; driver < ecpu_drivers; driver++) { + struct cpu_device_id *id; + for (id = driver->id_table; + id->vendor != X86_VENDOR_INVALID; id++) { + if ((cpu->vendor == id->vendor) && + (cpu->device == id->device)) + { + return driver; + } + if (X86_VENDOR_ANY == id->vendor) + return driver; + } + } + return NULL; +} + +static void set_cpu_ops(struct device *cpu) +{ + struct cpu_driver *driver = find_cpu_driver(cpu); + cpu->ops = driver ? driver->ops : NULL; +} + +void cpu_initialize(unsigned int index) +{ + /* Because we busy wait at the printk spinlock. + * It is important to keep the number of printed messages + * from secondary cpus to a minimum, when debugging is + * disabled. + */ + struct device *cpu; + struct cpu_info *info; + struct cpuinfo_x86 c; + + info = cpu_info(); + + printk(BIOS_INFO, "Initializing CPU #%d\n", index); + + cpu = info->cpu; + if (!cpu) { + die("CPU: missing cpu device structure"); + } + + post_log_path(cpu); + + /* Find what type of cpu we are dealing with */ + identify_cpu(cpu); + printk(BIOS_DEBUG, "CPU: vendor %s device %x\n", + cpu_vendor_name(cpu->vendor), cpu->device); + + get_fms(&c, cpu->device); + + printk(BIOS_DEBUG, "CPU: family %02x, model %02x, stepping %02x\n", + c.x86, c.x86_model, c.x86_mask); + + /* Lookup the cpu's operations */ + set_cpu_ops(cpu); + + if(!cpu->ops) { + /* mask out the stepping and try again */ + cpu->device -= c.x86_mask; + set_cpu_ops(cpu); + cpu->device += c.x86_mask; + if(!cpu->ops) die("Unknown cpu"); + printk(BIOS_DEBUG, "Using generic cpu ops (good)\n"); + } + + + /* Initialize the cpu */ + if (cpu->ops && cpu->ops->init) { + cpu->enabled = 1; + cpu->initialized = 1; + cpu->ops->init(cpu); + } + post_log_clear(); + + printk(BIOS_INFO, "CPU #%d initialized\n", index); + + return; +} diff --git a/src/arch/x86/cpu_common.c b/src/arch/x86/cpu_common.c new file mode 100644 index 0000000000..af0ab2ae98 --- /dev/null +++ b/src/arch/x86/cpu_common.c @@ -0,0 +1,65 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#ifndef __x86_64__ +/* Standard macro to see if a specific flag is changeable */ +static inline int flag_is_changeable_p(uint32_t flag) +{ + uint32_t f1, f2; + + asm( + "pushfl\n\t" + "pushfl\n\t" + "popl %0\n\t" + "movl %0,%1\n\t" + "xorl %2,%0\n\t" + "pushl %0\n\t" + "popfl\n\t" + "pushfl\n\t" + "popl %0\n\t" + "popfl\n\t" + : "=&r" (f1), "=&r" (f2) + : "ir" (flag)); + return ((f1^f2) & flag) != 0; +} + +/* Probe for the CPUID instruction */ +int cpu_have_cpuid(void) +{ + return flag_is_changeable_p(X86_EFLAGS_ID); +} + +#else + +int cpu_have_cpuid(void) +{ + return 1; +} +#endif + +int cpu_cpuid_extended_level(void) +{ + return cpuid_eax(0x80000000); +} + +int cpu_phys_address_size(void) +{ + if (!(cpu_have_cpuid())) + return 32; + + if (cpu_cpuid_extended_level() >= 0x80000008) + return cpuid_eax(0x80000008) & 0xff; + + if (cpuid_edx(1) & (CPUID_FEATURE_PAE | CPUID_FEATURE_PSE36)) + return 36; + return 32; +} diff --git a/src/arch/x86/crt0_romcc_epilogue.inc b/src/arch/x86/crt0_romcc_epilogue.inc new file mode 100644 index 0000000000..ff93adbc70 --- /dev/null +++ b/src/arch/x86/crt0_romcc_epilogue.inc @@ -0,0 +1,21 @@ +/* + * Copyright 2002 Eric Biederman + * + * This file is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; version 2 of the License. + */ +#include + +__main: + post_code(POST_PREPARE_RAMSTAGE) + cld /* clear direction flag */ + + movl $CONFIG_RAMTOP, %esp + movl %esp, %ebp + call copy_and_run + +.Lhlt: + post_code(POST_DEAD_CODE) + hlt + jmp .Lhlt diff --git a/src/arch/x86/ebda.c b/src/arch/x86/ebda.c new file mode 100644 index 0000000000..47dfbdb1e9 --- /dev/null +++ b/src/arch/x86/ebda.c @@ -0,0 +1,52 @@ +/* + * This file is part of the coreboot project. + * + * Copyright (C) 2012 The Chromium OS Authors. All rights reserved. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; version 2 of + * the License. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc. + */ + +#include +#include +#include +#include +#include + +void setup_ebda(u32 low_memory_size, u16 ebda_segment, u16 ebda_size) +{ + /* Skip in S3 resume path */ + if (acpi_is_wakeup_s3()) + return; + + if (!low_memory_size || !ebda_segment || !ebda_size) + return; + + /* clear BIOS DATA AREA */ + memset((void *)X86_BDA_BASE, 0, X86_BDA_SIZE); + + write16(X86_EBDA_LOWMEM, (low_memory_size >> 10)); + write16(X86_EBDA_SEGMENT, ebda_segment); + + /* Set up EBDA */ + memset((void *)((uintptr_t)ebda_segment << 4), 0, ebda_size); + write16((void*)((uintptr_t)ebda_segment << 4), (ebda_size >> 10)); +} + +void setup_default_ebda(void) +{ + setup_ebda(DEFAULT_EBDA_LOWMEM, + DEFAULT_EBDA_SEGMENT, + DEFAULT_EBDA_SIZE); +} diff --git a/src/arch/x86/exception.c b/src/arch/x86/exception.c new file mode 100644 index 0000000000..65181e224e --- /dev/null +++ b/src/arch/x86/exception.c @@ -0,0 +1,511 @@ +#include +#include +#include + +#if CONFIG_GDB_STUB + +/* BUFMAX defines the maximum number of characters in inbound/outbound buffers. + * At least NUM_REGBYTES*2 are needed for register packets + */ +#define BUFMAX 400 +enum regnames { + EAX = 0, ECX, EDX, EBX, ESP, EBP, ESI, EDI, + PC /* also known as eip */, + PS /* also known as eflags */, + CS, SS, DS, ES, FS, GS, + NUM_REGS /* Number of registers. */ +}; + +static uint32_t gdb_stub_registers[NUM_REGS]; + +#define GDB_SIG0 0 /* Signal 0 */ +#define GDB_SIGHUP 1 /* Hangup */ +#define GDB_SIGINT 2 /* Interrupt */ +#define GDB_SIGQUIT 3 /* Quit */ +#define GDB_SIGILL 4 /* Illegal instruction */ +#define GDB_SIGTRAP 5 /* Trace/breakpoint trap */ +#define GDB_SIGABRT 6 /* Aborted */ +#define GDB_SIGEMT 7 /* Emulation trap */ +#define GDB_SIGFPE 8 /* Arithmetic exception */ +#define GDB_SIGKILL 9 /* Killed */ +#define GDB_SIGBUS 10 /* Bus error */ +#define GDB_SIGSEGV 11 /* Segmentation fault */ +#define GDB_SIGSYS 12 /* Bad system call */ +#define GDB_SIGPIPE 13 /* Broken pipe */ +#define GDB_SIGALRM 14 /* Alarm clock */ +#define GDB_SIGTERM 15 /* Terminated */ +#define GDB_SIGURG 16 /* Urgent I/O condition */ +#define GDB_SIGSTOP 17 /* Stopped (signal) */ +#define GDB_SIGTSTP 18 /* Stopped (user) */ +#define GDB_SIGCONT 19 /* Continued */ +#define GDB_SIGCHLD 20 /* Child status changed */ +#define GDB_SIGTTIN 21 /* Stopped (tty input) */ +#define GDB_SIGTTOU 22 /* Stopped (tty output) */ +#define GDB_SIGIO 23 /* I/O possible */ +#define GDB_SIGXCPU 24 /* CPU time limit exceeded */ +#define GDB_SIGXFSZ 25 /* File size limit exceeded */ +#define GDB_SIGVTALRM 26 /* Virtual timer expired */ +#define GDB_SIGPROF 27 /* Profiling timer expired */ +#define GDB_SIGWINCH 28 /* Window size changed */ +#define GDB_SIGLOST 29 /* Resource lost */ +#define GDB_SIGUSR1 30 /* User defined signal 1 */ +#define GDB_SUGUSR2 31 /* User defined signal 2 */ +#define GDB_SIGPWR 32 /* Power fail/restart */ +#define GDB_SIGPOLL 33 /* Pollable event occurred */ +#define GDB_SIGWIND 34 /* SIGWIND */ +#define GDB_SIGPHONE 35 /* SIGPHONE */ +#define GDB_SIGWAITING 36 /* Process's LWPs are blocked */ +#define GDB_SIGLWP 37 /* Signal LWP */ +#define GDB_SIGDANGER 38 /* Swap space dangerously low */ +#define GDB_SIGGRANT 39 /* Monitor mode granted */ +#define GDB_SIGRETRACT 40 /* Need to relinquish monitor mode */ +#define GDB_SIGMSG 41 /* Monitor mode data available */ +#define GDB_SIGSOUND 42 /* Sound completed */ +#define GDB_SIGSAK 43 /* Secure attention */ +#define GDB_SIGPRIO 44 /* SIGPRIO */ + +#define GDB_SIG33 45 /* Real-time event 33 */ +#define GDB_SIG34 46 /* Real-time event 34 */ +#define GDB_SIG35 47 /* Real-time event 35 */ +#define GDB_SIG36 48 /* Real-time event 36 */ +#define GDB_SIG37 49 /* Real-time event 37 */ +#define GDB_SIG38 50 /* Real-time event 38 */ +#define GDB_SIG39 51 /* Real-time event 39 */ +#define GDB_SIG40 52 /* Real-time event 40 */ +#define GDB_SIG41 53 /* Real-time event 41 */ +#define GDB_SIG42 54 /* Real-time event 42 */ +#define GDB_SIG43 55 /* Real-time event 43 */ +#define GDB_SIG44 56 /* Real-time event 44 */ +#define GDB_SIG45 57 /* Real-time event 45 */ +#define GDB_SIG46 58 /* Real-time event 46 */ +#define GDB_SIG47 59 /* Real-time event 47 */ +#define GDB_SIG48 60 /* Real-time event 48 */ +#define GDB_SIG49 61 /* Real-time event 49 */ +#define GDB_SIG50 62 /* Real-time event 50 */ +#define GDB_SIG51 63 /* Real-time event 51 */ +#define GDB_SIG52 64 /* Real-time event 52 */ +#define GDB_SIG53 65 /* Real-time event 53 */ +#define GDB_SIG54 66 /* Real-time event 54 */ +#define GDB_SIG55 67 /* Real-time event 55 */ +#define GDB_SIG56 68 /* Real-time event 56 */ +#define GDB_SIG57 69 /* Real-time event 57 */ +#define GDB_SIG58 70 /* Real-time event 58 */ +#define GDB_SIG59 71 /* Real-time event 59 */ +#define GDB_SIG60 72 /* Real-time event 60 */ +#define GDB_SIG61 73 /* Real-time event 61 */ +#define GDB_SIG62 74 /* Real-time event 62 */ +#define GDB_SIG63 75 /* Real-time event 63 */ +#define GDB_SIGCANCEL 76 /* LWP internal signal */ +#define GDB_SIG32 77 /* Real-time event 32 */ +#define GDB_SIG64 78 /* Real-time event 64 */ +#define GDB_SIG65 79 /* Real-time event 65 */ +#define GDB_SIG66 80 /* Real-time event 66 */ +#define GDB_SIG67 81 /* Real-time event 67 */ +#define GDB_SIG68 82 /* Real-time event 68 */ +#define GDB_SIG69 83 /* Real-time event 69 */ +#define GDB_SIG70 84 /* Real-time event 70 */ +#define GDB_SIG71 85 /* Real-time event 71 */ +#define GDB_SIG72 86 /* Real-time event 72 */ +#define GDB_SIG73 87 /* Real-time event 73 */ +#define GDB_SIG74 88 /* Real-time event 74 */ +#define GDB_SIG75 89 /* Real-time event 75 */ +#define GDB_SIG76 90 /* Real-time event 76 */ +#define GDB_SIG77 91 /* Real-time event 77 */ +#define GDB_SIG78 92 /* Real-time event 78 */ +#define GDB_SIG79 93 /* Real-time event 79 */ +#define GDB_SIG80 94 /* Real-time event 80 */ +#define GDB_SIG81 95 /* Real-time event 81 */ +#define GDB_SIG82 96 /* Real-time event 82 */ +#define GDB_SIG83 97 /* Real-time event 83 */ +#define GDB_SIG84 98 /* Real-time event 84 */ +#define GDB_SIG85 99 /* Real-time event 85 */ +#define GDB_SIG86 100 /* Real-time event 86 */ +#define GDB_SIG87 101 /* Real-time event 87 */ +#define GDB_SIG88 102 /* Real-time event 88 */ +#define GDB_SIG89 103 /* Real-time event 89 */ +#define GDB_SIG90 104 /* Real-time event 90 */ +#define GDB_SIG91 105 /* Real-time event 91 */ +#define GDB_SIG92 106 /* Real-time event 92 */ +#define GDB_SIG93 107 /* Real-time event 93 */ +#define GDB_SIG94 108 /* Real-time event 94 */ +#define GDB_SIG95 109 /* Real-time event 95 */ +#define GDB_SIG96 110 /* Real-time event 96 */ +#define GDB_SIG97 111 /* Real-time event 97 */ +#define GDB_SIG98 112 /* Real-time event 98 */ +#define GDB_SIG99 113 /* Real-time event 99 */ +#define GDB_SIG100 114 /* Real-time event 100 */ +#define GDB_SIG101 115 /* Real-time event 101 */ +#define GDB_SIG102 116 /* Real-time event 102 */ +#define GDB_SIG103 117 /* Real-time event 103 */ +#define GDB_SIG104 118 /* Real-time event 104 */ +#define GDB_SIG105 119 /* Real-time event 105 */ +#define GDB_SIG106 120 /* Real-time event 106 */ +#define GDB_SIG107 121 /* Real-time event 107 */ +#define GDB_SIG108 122 /* Real-time event 108 */ +#define GDB_SIG109 123 /* Real-time event 109 */ +#define GDB_SIG110 124 /* Real-time event 110 */ +#define GDB_SIG111 125 /* Real-time event 111 */ +#define GDB_SIG112 126 /* Real-time event 112 */ +#define GDB_SIG113 127 /* Real-time event 113 */ +#define GDB_SIG114 128 /* Real-time event 114 */ +#define GDB_SIG115 129 /* Real-time event 115 */ +#define GDB_SIG116 130 /* Real-time event 116 */ +#define GDB_SIG117 131 /* Real-time event 117 */ +#define GDB_SIG118 132 /* Real-time event 118 */ +#define GDB_SIG119 133 /* Real-time event 119 */ +#define GDB_SIG120 134 /* Real-time event 120 */ +#define GDB_SIG121 135 /* Real-time event 121 */ +#define GDB_SIG122 136 /* Real-time event 122 */ +#define GDB_SIG123 137 /* Real-time event 123 */ +#define GDB_SIG124 138 /* Real-time event 124 */ +#define GDB_SIG125 139 /* Real-time event 125 */ +#define GDB_SIG126 140 /* Real-time event 126 */ +#define GDB_SIG127 141 /* Real-time event 127 */ +#define GDB_SIGINFO 142 /* Information request */ +#define GDB_UNKNOWN 143 /* Unknown signal */ +#define GDB_DEFAULT 144 /* error: default signal */ +/* Mach exceptions */ +#define GDB_EXC_BAD_ACCESS 145 /* Could not access memory */ +#define GDB_EXC_BAD_INSTRCTION 146 /* Illegal instruction/operand */ +#define GDB_EXC_ARITHMETIC 147 /* Arithmetic exception */ +#define GDB_EXC_EMULATION 148 /* Emulation instruction */ +#define GDB_EXC_SOFTWARE 149 /* Software generated exception */ +#define GDB_EXC_BREAKPOINT 150 /* Breakpoint */ + + + +static unsigned char exception_to_signal[] = +{ + [0] = GDB_SIGFPE, /* divide by zero */ + [1] = GDB_SIGTRAP, /* debug exception */ + [2] = GDB_SIGSEGV, /* NMI Interrupt */ + [3] = GDB_SIGTRAP, /* Breakpoint */ + [4] = GDB_SIGSEGV, /* into instruction (overflow) */ + [5] = GDB_SIGSEGV, /* bound instruction */ + [6] = GDB_SIGILL, /* Invalid opcode */ + [7] = GDB_SIGSEGV, /* coprocessor not available */ + [8] = GDB_SIGSEGV, /* double fault */ + [9] = GDB_SIGFPE, /* coprocessor segment overrun */ + [10] = GDB_SIGSEGV, /* Invalid TSS */ + [11] = GDB_SIGBUS, /* Segment not present */ + [12] = GDB_SIGBUS, /* stack exception */ + [13] = GDB_SIGSEGV, /* general protection */ + [14] = GDB_SIGSEGV, /* page fault */ + [15] = GDB_UNKNOWN, /* reserved */ + [16] = GDB_SIGEMT, /* coprocessor error */ + [17] = GDB_SIGBUS, /* alignment check */ + [18] = GDB_SIGSEGV, /* machine check */ + [19] = GDB_SIGFPE, /* simd floating point exception */ + [20] = GDB_UNKNOWN, + [21] = GDB_UNKNOWN, + [22] = GDB_UNKNOWN, + [23] = GDB_UNKNOWN, + [24] = GDB_UNKNOWN, + [25] = GDB_UNKNOWN, + [26] = GDB_UNKNOWN, + [27] = GDB_UNKNOWN, + [28] = GDB_UNKNOWN, + [29] = GDB_UNKNOWN, + [30] = GDB_UNKNOWN, + [31] = GDB_UNKNOWN, + [32] = GDB_SIGINT, /* User interrupt */ +}; + +static const char hexchars[] = "0123456789abcdef"; +static char in_buffer[BUFMAX]; +static char out_buffer[BUFMAX]; + + +static inline void stub_putc(int ch) +{ + gdb_tx_byte(ch); +} + +static inline void stub_flush(void) +{ + gdb_tx_flush(); +} + +static inline int stub_getc(void) +{ + return gdb_rx_byte(); +} + +static int hex(char ch) +{ + if ((ch >= 'a') && (ch <= 'f')) + return (ch - 'a' + 10); + if ((ch >= '0') && (ch <= '9')) + return (ch - '0'); + if ((ch >= 'A') && (ch <= 'F')) + return (ch - 'A' + 10); + return (-1); +} + +/* + * While we find hexadecimal digits, build an int. + * Fals is returned if nothing is parsed true otherwise. + */ +static int parse_ulong(char **ptr, unsigned long *value) +{ + int digit; + char *start; + + start = *ptr; + *value = 0; + + while((digit = hex(**ptr)) >= 0) { + *value = ((*value) << 4) | digit; + (*ptr)++; + } + return start != *ptr; +} + +/* convert the memory pointed to by mem into hex, placing result in buf */ +/* return a pointer to the last char put in buf (null) */ +static void copy_to_hex(char *buf, void *addr, unsigned long count) +{ + unsigned char ch; + char *mem = addr; + + while(count--) { + ch = *mem++; + *buf++ = hexchars[ch >> 4]; + *buf++ = hexchars[ch & 0x0f]; + } + *buf = 0; + return; +} + + +/* convert the hex array pointed to by buf into binary to be placed in mem */ +/* return a pointer to the character AFTER the last byte written */ +static void copy_from_hex(void *addr, char *buf, unsigned long count) +{ + unsigned char ch; + char *mem = addr; + + while(count--) { + ch = hex (*buf++) << 4; + ch = ch + hex (*buf++); + *mem++ = ch; + } +} + + +/* scan for the sequence $# */ + +static int get_packet(char *buffer) +{ + unsigned char checksum; + unsigned char xmitcsum; + int count; + char ch; + + /* Wishlit implement a timeout in get_packet */ + do { + /* wait around for the start character, ignore all other characters */ + while ((ch = (stub_getc() & 0x7f)) != '$'); + checksum = 0; + xmitcsum = -1; + + count = 0; + + /* now, read until a # or end of buffer is found */ + while (count < BUFMAX) { + ch = stub_getc() & 0x7f; + if (ch == '#') + break; + checksum = checksum + ch; + buffer[count] = ch; + count = count + 1; + } + buffer[count] = 0; + + if (ch == '#') { + xmitcsum = hex(stub_getc() & 0x7f) << 4; + xmitcsum += hex(stub_getc() & 0x7f); + + if (checksum != xmitcsum) { + stub_putc('-'); /* failed checksum */ + stub_flush(); + } + else { + stub_putc('+'); /* successful transfer */ + stub_flush(); + } + } + } while(checksum != xmitcsum); + return 1; +} + +/* send the packet in buffer.*/ +static void put_packet(char *buffer) +{ + unsigned char checksum; + int count; + char ch; + + /* $#. */ + do { + stub_putc('$'); + checksum = 0; + count = 0; + + while ((ch = buffer[count])) { + stub_putc(ch); + checksum += ch; + count += 1; + } + + stub_putc('#'); + stub_putc(hexchars[checksum >> 4]); + stub_putc(hexchars[checksum % 16]); + stub_flush(); + + } while ((stub_getc() & 0x7f) != '+'); + +} +#endif /* CONFIG_GDB_STUB */ + +#include + +void x86_exception(struct eregs *info); + +void x86_exception(struct eregs *info) +{ +#if CONFIG_GDB_STUB + int signo; + memcpy(gdb_stub_registers, info, 8*sizeof(uint32_t)); + gdb_stub_registers[PC] = info->eip; + gdb_stub_registers[CS] = info->cs; + gdb_stub_registers[PS] = info->eflags; + signo = GDB_UNKNOWN; + if (info->vector < ARRAY_SIZE(exception_to_signal)) { + signo = exception_to_signal[info->vector]; + } + + /* reply to the host that an exception has occured */ + out_buffer[0] = 'S'; + out_buffer[1] = hexchars[(signo>>4) & 0xf]; + out_buffer[2] = hexchars[signo & 0xf]; + out_buffer[3] = '\0'; + put_packet(out_buffer); + + while(1) { + unsigned long addr, length; + char *ptr; + out_buffer[0] = '\0'; + out_buffer[1] = '\0'; + if (!get_packet(in_buffer)) { + break; + } + switch(in_buffer[0]) { + case '?': /* last signal */ + out_buffer[0] = 'S'; + out_buffer[1] = hexchars[(signo >> 4) & 0xf]; + out_buffer[2] = hexchars[signo & 0xf]; + out_buffer[3] = '\0'; + break; + case 'g': /* return the value of the cpu registers */ + copy_to_hex(out_buffer, &gdb_stub_registers, sizeof(gdb_stub_registers)); + break; + case 'G': /* set the value of the CPU registers - return OK */ + copy_from_hex(&gdb_stub_registers, in_buffer + 1, sizeof(gdb_stub_registers)); + memcpy(info, gdb_stub_registers, 8*sizeof(uint32_t)); + info->eip = gdb_stub_registers[PC]; + info->cs = gdb_stub_registers[CS]; + info->eflags = gdb_stub_registers[PS]; + memcpy(out_buffer, "OK",3); + break; + case 'm': + /* mAA..AA,LLLL Read LLLL bytes at address AA..AA */ + ptr = &in_buffer[1]; + if ( parse_ulong(&ptr, &addr) && + (*ptr++ == ',') && + parse_ulong(&ptr, &length)) { + copy_to_hex(out_buffer, (void *)addr, length); + } else { + memcpy(out_buffer, "E01", 4); + } + break; + case 'M': + /* MAA..AA,LLLL: Write LLLL bytes at address AA.AA return OK */ + ptr = &in_buffer[1]; + if ( parse_ulong(&ptr, &addr) && + (*(ptr++) == ',') && + parse_ulong(&ptr, &length) && + (*(ptr++) == ':')) { + copy_from_hex((void *)addr, ptr, length); + memcpy(out_buffer, "OK", 3); + } + else { + memcpy(out_buffer, "E02", 4); + } + break; + case 's': + case 'c': + /* cAA..AA Continue at address AA..AA(optional) */ + /* sAA..AA Step one instruction from AA..AA(optional) */ + ptr = &in_buffer[1]; + if (parse_ulong(&ptr, &addr)) { + info->eip = addr; + } + + /* Clear the trace bit */ + info->eflags &= ~(1 << 8); + /* Set the trace bit if we are single stepping */ + if (in_buffer[0] == 's') { + info->eflags |= (1 << 8); + } + return; + break; + case 'D': + memcpy(out_buffer, "OK", 3); + break; + case 'k': /* kill request? */ + break; + case 'q': /* query */ + break; + case 'z': /* z0AAAA,LLLL remove memory breakpoint */ + /* z1AAAA,LLLL remove hardware breakpoint */ + /* z2AAAA,LLLL remove write watchpoint */ + /* z3AAAA,LLLL remove read watchpoint */ + /* z4AAAA,LLLL remove access watchpoint */ + case 'Z': /* Z0AAAA,LLLL insert memory breakpoint */ + /* Z1AAAA,LLLL insert hardware breakpoint */ + /* Z2AAAA,LLLL insert write watchpoint */ + /* Z3AAAA,LLLL insert read watchpoint */ + /* Z4AAAA,LLLL insert access watchpoint */ + break; + default: + break; + } + put_packet(out_buffer); + } +#else /* !CONFIG_GDB_STUB */ +#define MDUMP_SIZE 0x80 + printk(BIOS_EMERG, + "Unexpected Exception: %d @ %02x:%08x - Halting\n" + "Code: %d eflags: %08x\n" + "eax: %08x ebx: %08x ecx: %08x edx: %08x\n" + "edi: %08x esi: %08x ebp: %08x esp: %08x\n", + info->vector, info->cs, info->eip, + info->error_code, info->eflags, + info->eax, info->ebx, info->ecx, info->edx, + info->edi, info->esi, info->ebp, info->esp); + u8 *code = (u8*)((uintptr_t)info->eip - (MDUMP_SIZE >>1)); + /* Align to 8-byte boundary please, and print eight bytes per row. + * This is done to make DRAM burst timing/reordering errors more + * evident from the looking at the dump */ + code = (u8*)((uintptr_t)code & ~0x7); + int i; + for(i = 0; i < MDUMP_SIZE; i++) + { + if( (i & 0x07) == 0 ) + printk(BIOS_EMERG, "\n%p:\t", code + i); + printk(BIOS_EMERG, "%.2x ", code[i]); + } + die(""); +#endif +} diff --git a/src/arch/x86/failover.ld b/src/arch/x86/failover.ld new file mode 100644 index 0000000000..d7aa47e249 --- /dev/null +++ b/src/arch/x86/failover.ld @@ -0,0 +1,70 @@ +/* + * This file is part of the coreboot project. + * + * Copyright (C) 2006 Advanced Micro Devices, Inc. + * Copyright (C) 2008-2010 coresystems GmbH + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; version 2 of the License. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc. + */ + +MEMORY { + rom : ORIGIN = 0xffff0000, LENGTH = 64K +} + +TARGET(binary) +SECTIONS +{ + /* Symbol ap_sipi_vector must be aligned to 4kB to start AP CPUs + * with Startup IPI message without RAM. Align .rom to next 4 byte + * boundary anyway, so no pad byte appears between _rom and _start. + */ + .bogus ROMLOC_MIN : { + . = CONFIG_SIPI_VECTOR_IN_ROM ? ALIGN(4096) : ALIGN(4); + ROMLOC = .; + } >rom = 0xff + + /* This section might be better named .setup */ + .rom ROMLOC : { + _rom = .; + ap_sipi_vector = .; + *(.rom.text); + *(.rom.data); + *(.rom.data.*); + *(.rodata.*); + _erom = .; + } >rom = 0xff + + /* Allocation reserves extra 16 bytes here. Alignment requirements + * may cause the total size of a section to change when the start + * address gets applied. + */ + ROMLOC_MIN = 0xffffff00 - (_erom - _rom + 16) - + (CONFIG_SIPI_VECTOR_IN_ROM ? 4096 : 0); + + /* Post-check proper SIPI vector. */ + _bogus = ASSERT(!CONFIG_SIPI_VECTOR_IN_ROM || ((ap_sipi_vector & 0x0fff) == 0x0), + "Bad SIPI vector alignment"); + _bogus = ASSERT(!CONFIG_SIPI_VECTOR_IN_ROM || (ap_sipi_vector == CONFIG_AP_SIPI_VECTOR), + "Address mismatch on AP_SIPI_VECTOR"); + + /DISCARD/ : { + *(.comment) + *(.note) + *(.comment.*) + *(.note.*) + *(.iplt) + *(.rel.*) + *(.igot.*) + } +} diff --git a/src/arch/x86/gdt.c b/src/arch/x86/gdt.c new file mode 100644 index 0000000000..a21fab24ad --- /dev/null +++ b/src/arch/x86/gdt.c @@ -0,0 +1,62 @@ +/* + * This file is part of the coreboot project. + * + * Copyright (C) 2008-2009 coresystems GmbH + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; version 2 of the License. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc. + */ + +#include +#include +#include +#include +#include + +/* i386 lgdt argument */ +struct gdtarg { + u16 limit; +#ifdef __x86_64__ + u64 base; +#else + u32 base; +#endif +} __attribute__((packed)); + +/* Copy GDT to new location and reload it. + * FIXME: We only do this for BSP CPU. + */ +static void move_gdt(int is_recovery) +{ + void *newgdt; + u16 num_gdt_bytes = (uintptr_t)&gdt_end - (uintptr_t)&gdt; + struct gdtarg gdtarg; + + newgdt = cbmem_find(CBMEM_ID_GDT); + if (!newgdt) { + newgdt = cbmem_add(CBMEM_ID_GDT, ALIGN(num_gdt_bytes, 512)); + if (!newgdt) { + printk(BIOS_ERR, "Error: Could not relocate GDT.\n"); + return; + } + printk(BIOS_DEBUG, "Moving GDT to %p...", newgdt); + memcpy((void*)newgdt, &gdt, num_gdt_bytes); + } + + gdtarg.base = (uintptr_t)newgdt; + gdtarg.limit = num_gdt_bytes - 1; + + __asm__ __volatile__ ("lgdt %0\n\t" : : "m" (gdtarg)); + printk(BIOS_DEBUG, "ok\n"); +} +RAMSTAGE_CBMEM_INIT_HOOK(move_gdt) diff --git a/src/arch/x86/id.inc b/src/arch/x86/id.inc new file mode 100644 index 0000000000..f8aba0b946 --- /dev/null +++ b/src/arch/x86/id.inc @@ -0,0 +1,18 @@ + .section ".id", "a", @progbits + + .globl __id_start +__id_start: +ver: + .asciz COREBOOT_VERSION +vendor: + .asciz CONFIG_MAINBOARD_VENDOR +part: + .asciz CONFIG_MAINBOARD_PART_NUMBER +.long __id_end + CONFIG_ID_SECTION_OFFSET - ver /* Reverse offset to the vendor id */ +.long __id_end + CONFIG_ID_SECTION_OFFSET - vendor /* Reverse offset to the vendor id */ +.long __id_end + CONFIG_ID_SECTION_OFFSET - part /* Reverse offset to the part number */ +.long CONFIG_ROM_SIZE /* Size of this romimage */ + .globl __id_end + +__id_end: +.previous diff --git a/src/arch/x86/id.ld b/src/arch/x86/id.ld new file mode 100644 index 0000000000..cfd091dc17 --- /dev/null +++ b/src/arch/x86/id.ld @@ -0,0 +1,6 @@ +SECTIONS { + . = (0xffffffff - CONFIG_ID_SECTION_OFFSET) - (__id_end - __id_start) + 1; + .id (.): { + *(.id) + } +} diff --git a/src/arch/x86/init/Makefile.inc b/src/arch/x86/init/Makefile.inc deleted file mode 100644 index 263c58e891..0000000000 --- a/src/arch/x86/init/Makefile.inc +++ /dev/null @@ -1 +0,0 @@ -# If you add something to this file, enable it in src/arch/x86/Makefile.inc first. diff --git a/src/arch/x86/init/bootblock_normal.c b/src/arch/x86/init/bootblock_normal.c deleted file mode 100644 index bde2535ba6..0000000000 --- a/src/arch/x86/init/bootblock_normal.c +++ /dev/null @@ -1,52 +0,0 @@ -#include -#include -#include -#include - -static const char *get_fallback(const char *stagelist) { - while (*stagelist) stagelist++; - return ++stagelist; -} - -static void main(unsigned long bist) -{ - unsigned long entry; - int boot_mode; - const char *default_filenames = "normal/romstage\0fallback/romstage"; - - if (boot_cpu()) { - bootblock_mainboard_init(); - -#if CONFIG_USE_OPTION_TABLE - sanitize_cmos(); -#endif - boot_mode = do_normal_boot(); - } else { - - /* Questionable single byte read from CMOS. - * Do not add any other CMOS access in the - * bootblock for AP CPUs. - */ - boot_mode = last_boot_normal(); - } - - char *filenames = (char *)walkcbfs("coreboot-stages"); - if (!filenames) { - filenames = default_filenames; - } - char *normal_candidate = filenames; - - if (boot_mode) - entry = findstage(normal_candidate); - else - entry = findstage(get_fallback(normal_candidate)); - - if (entry) call(entry, bist); - - /* run fallback if normal can't be found */ - entry = findstage(get_fallback(normal_candidate)); - if (entry) call(entry, bist); - - /* duh. we're stuck */ - halt(); -} diff --git a/src/arch/x86/init/bootblock_simple.c b/src/arch/x86/init/bootblock_simple.c deleted file mode 100644 index adeecf7ba6..0000000000 --- a/src/arch/x86/init/bootblock_simple.c +++ /dev/null @@ -1,23 +0,0 @@ -#include -#include -#include - -static void main(unsigned long bist) -{ - if (boot_cpu()) { - bootblock_mainboard_init(); - -#if CONFIG_USE_OPTION_TABLE - sanitize_cmos(); -#endif -#if CONFIG_CMOS_POST - cmos_post_init(); -#endif - } - - const char* target1 = "fallback/romstage"; - unsigned long entry; - entry = findstage(target1); - if (entry) call(entry, bist); - halt(); -} diff --git a/src/arch/x86/init/crt0_romcc_epilogue.inc b/src/arch/x86/init/crt0_romcc_epilogue.inc deleted file mode 100644 index ff93adbc70..0000000000 --- a/src/arch/x86/init/crt0_romcc_epilogue.inc +++ /dev/null @@ -1,21 +0,0 @@ -/* - * Copyright 2002 Eric Biederman - * - * This file is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation; version 2 of the License. - */ -#include - -__main: - post_code(POST_PREPARE_RAMSTAGE) - cld /* clear direction flag */ - - movl $CONFIG_RAMTOP, %esp - movl %esp, %ebp - call copy_and_run - -.Lhlt: - post_code(POST_DEAD_CODE) - hlt - jmp .Lhlt diff --git a/src/arch/x86/init/failover.ld b/src/arch/x86/init/failover.ld deleted file mode 100644 index d7aa47e249..0000000000 --- a/src/arch/x86/init/failover.ld +++ /dev/null @@ -1,70 +0,0 @@ -/* - * This file is part of the coreboot project. - * - * Copyright (C) 2006 Advanced Micro Devices, Inc. - * Copyright (C) 2008-2010 coresystems GmbH - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; version 2 of the License. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc. - */ - -MEMORY { - rom : ORIGIN = 0xffff0000, LENGTH = 64K -} - -TARGET(binary) -SECTIONS -{ - /* Symbol ap_sipi_vector must be aligned to 4kB to start AP CPUs - * with Startup IPI message without RAM. Align .rom to next 4 byte - * boundary anyway, so no pad byte appears between _rom and _start. - */ - .bogus ROMLOC_MIN : { - . = CONFIG_SIPI_VECTOR_IN_ROM ? ALIGN(4096) : ALIGN(4); - ROMLOC = .; - } >rom = 0xff - - /* This section might be better named .setup */ - .rom ROMLOC : { - _rom = .; - ap_sipi_vector = .; - *(.rom.text); - *(.rom.data); - *(.rom.data.*); - *(.rodata.*); - _erom = .; - } >rom = 0xff - - /* Allocation reserves extra 16 bytes here. Alignment requirements - * may cause the total size of a section to change when the start - * address gets applied. - */ - ROMLOC_MIN = 0xffffff00 - (_erom - _rom + 16) - - (CONFIG_SIPI_VECTOR_IN_ROM ? 4096 : 0); - - /* Post-check proper SIPI vector. */ - _bogus = ASSERT(!CONFIG_SIPI_VECTOR_IN_ROM || ((ap_sipi_vector & 0x0fff) == 0x0), - "Bad SIPI vector alignment"); - _bogus = ASSERT(!CONFIG_SIPI_VECTOR_IN_ROM || (ap_sipi_vector == CONFIG_AP_SIPI_VECTOR), - "Address mismatch on AP_SIPI_VECTOR"); - - /DISCARD/ : { - *(.comment) - *(.note) - *(.comment.*) - *(.note.*) - *(.iplt) - *(.rel.*) - *(.igot.*) - } -} diff --git a/src/arch/x86/init/prologue.inc b/src/arch/x86/init/prologue.inc deleted file mode 100644 index e0100b5127..0000000000 --- a/src/arch/x86/init/prologue.inc +++ /dev/null @@ -1,23 +0,0 @@ -/* - * This file is part of the coreboot project. - * - * Copyright (C) 2002 Eric Biederman - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; version 2 of the License. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc. - */ - -#include - -.section ".rom.data", "a", @progbits -.section ".rom.text", "ax", @progbits diff --git a/src/arch/x86/init/romstage.ld b/src/arch/x86/init/romstage.ld deleted file mode 100644 index 951ca656a3..0000000000 --- a/src/arch/x86/init/romstage.ld +++ /dev/null @@ -1,87 +0,0 @@ -/* - * This file is part of the coreboot project. - * - * Copyright (C) 2006 Advanced Micro Devices, Inc. - * Copyright (C) 2008-2010 coresystems GmbH - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; version 2 of the License. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc. - */ - -TARGET(binary) -SECTIONS -{ - . = ROMSTAGE_BASE; - - .rom . : { - _rom = .; - *(.rom.text); - *(.rom.text.*); - *(.text); - *(.text.*); - *(.rom.data); - . = ALIGN(4); - _cbmem_init_hooks = .; - KEEP(*(.rodata.cbmem_init_hooks)); - _ecbmem_init_hooks = .; - *(.rodata); - *(.rodata.*); - *(.rom.data.*); - . = ALIGN(16); - _erom = .; - } - - /DISCARD/ : { - *(.comment) - *(.note) - *(.comment.*) - *(.note.*) - *(.eh_frame); - } - - . = CONFIG_DCACHE_RAM_BASE; - .car.data . (NOLOAD) : { - _car_data_start = .; -#if IS_ENABLED(CONFIG_HAS_PRECBMEM_TIMESTAMP_REGION) - _timestamp = .; - . = . + 0x100; - _etimestamp = .; -#endif - *(.car.global_data); - _car_data_end = .; - /* The preram cbmem console area comes last to take advantage - * of a zero-sized array to hold the memconsole contents. - * However, collisions within the cache-as-ram region cannot be - * statically checked because the cache-as-ram region usage is - * cpu/chipset dependent. */ - _preram_cbmem_console = .; - _epreram_cbmem_console = . + (CONFIG_LATE_CBMEM_INIT ? 0 : 0xc00); - } - - /* Global variables are not allowed in romstage - * This section is checked during stage creation to ensure - * that there are no global variables present - */ - - . = 0xffffff00; - .illegal_globals . : { - *(EXCLUDE_FILE ("*/libagesa.*.a:" "*/buildOpts.romstage.o" "*/agesawrapper.romstage.o" "*/vendorcode/amd/agesa/*" "*/vendorcode/amd/cimx/*") .data) - *(EXCLUDE_FILE ("*/libagesa.*.a:" "*/buildOpts.romstage.o" "*/agesawrapper.romstage.o" "*/vendorcode/amd/agesa/*" "*/vendorcode/amd/cimx/*") .data.*) - *(.bss) - *(.bss.*) - *(.sbss) - *(.sbss.*) - } - - _bogus = ASSERT((CONFIG_DCACHE_RAM_SIZE == 0) || (SIZEOF(.car.data) + 0xc00 <= CONFIG_DCACHE_RAM_SIZE), "Cache as RAM area is too full"); -} diff --git a/src/arch/x86/ioapic.c b/src/arch/x86/ioapic.c new file mode 100644 index 0000000000..1b131278fd --- /dev/null +++ b/src/arch/x86/ioapic.c @@ -0,0 +1,153 @@ +/* + * This file is part of the coreboot project. + * + * Copyright (C) 2010 coresystems GmbH + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; version 2 of the License. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc. + */ + +#include +#include +#include +#include + +u32 io_apic_read(void *ioapic_base, u32 reg) +{ + write32(ioapic_base, reg); + return read32(ioapic_base + 0x10); +} + +void io_apic_write(void *ioapic_base, u32 reg, u32 value) +{ + write32(ioapic_base, reg); + write32(ioapic_base + 0x10, value); +} + +static int ioapic_interrupt_count(void *ioapic_base) +{ + /* Read the available number of interrupts. */ + int ioapic_interrupts = (io_apic_read(ioapic_base, 0x01) >> 16) & 0xff; + if (ioapic_interrupts == 0xff) + ioapic_interrupts = 23; + ioapic_interrupts += 1; /* Bits 23-16 specify the maximum redirection + entry, which is the number of interrupts + minus 1. */ + printk(BIOS_DEBUG, "IOAPIC: %d interrupts\n", ioapic_interrupts); + + return ioapic_interrupts; +} + +void clear_ioapic(void *ioapic_base) +{ + u32 low, high; + u32 i, ioapic_interrupts; + + printk(BIOS_DEBUG, "IOAPIC: Clearing IOAPIC at %p\n", ioapic_base); + + ioapic_interrupts = ioapic_interrupt_count(ioapic_base); + + low = DISABLED; + high = NONE; + + for (i = 0; i < ioapic_interrupts; i++) { + io_apic_write(ioapic_base, i * 2 + 0x10, low); + io_apic_write(ioapic_base, i * 2 + 0x11, high); + + printk(BIOS_SPEW, "IOAPIC: reg 0x%08x value 0x%08x 0x%08x\n", + i, high, low); + } + + if (io_apic_read(ioapic_base, 0x10) == 0xffffffff) { + printk(BIOS_WARNING, "IOAPIC not responding.\n"); + return; + } +} + +void set_ioapic_id(void *ioapic_base, u8 ioapic_id) +{ + u32 bsp_lapicid = lapicid(); + int i; + + printk(BIOS_DEBUG, "IOAPIC: Initializing IOAPIC at 0x%p\n", + ioapic_base); + printk(BIOS_DEBUG, "IOAPIC: Bootstrap Processor Local APIC = 0x%02x\n", + bsp_lapicid); + + if (ioapic_id) { + printk(BIOS_DEBUG, "IOAPIC: ID = 0x%02x\n", ioapic_id); + /* Set IOAPIC ID if it has been specified. */ + io_apic_write(ioapic_base, 0x00, + (io_apic_read(ioapic_base, 0x00) & 0xf0ffffff) | + (ioapic_id << 24)); + } + + printk(BIOS_SPEW, "IOAPIC: Dumping registers\n"); + for (i = 0; i < 3; i++) + printk(BIOS_SPEW, " reg 0x%04x: 0x%08x\n", i, + io_apic_read(ioapic_base, i)); + +} + +static void load_vectors(void *ioapic_base) +{ + u32 bsp_lapicid = lapicid(); + u32 low, high; + u32 i, ioapic_interrupts; + + ioapic_interrupts = ioapic_interrupt_count(ioapic_base); + +#if CONFIG_IOAPIC_INTERRUPTS_ON_FSB + /* + * For the Pentium 4 and above APICs deliver their interrupts + * on the front side bus, enable that. + */ + printk(BIOS_DEBUG, "IOAPIC: Enabling interrupts on FSB\n"); + io_apic_write(ioapic_base, 0x03, + io_apic_read(ioapic_base, 0x03) | (1 << 0)); +#endif +#if CONFIG_IOAPIC_INTERRUPTS_ON_APIC_SERIAL_BUS + printk(BIOS_DEBUG, "IOAPIC: Enabling interrupts on APIC serial bus\n"); + io_apic_write(ioapic_base, 0x03, 0); +#endif + + /* Enable Virtual Wire Mode. */ + low = ENABLED | TRIGGER_EDGE | POLARITY_HIGH | PHYSICAL_DEST | ExtINT; + high = bsp_lapicid << (56 - 32); + + io_apic_write(ioapic_base, 0x10, low); + io_apic_write(ioapic_base, 0x11, high); + + if (io_apic_read(ioapic_base, 0x10) == 0xffffffff) { + printk(BIOS_WARNING, "IOAPIC not responding.\n"); + return; + } + + printk(BIOS_SPEW, "IOAPIC: reg 0x%08x value 0x%08x 0x%08x\n", + 0, high, low); + low = DISABLED; + high = NONE; + for (i = 1; i < ioapic_interrupts; i++) { + io_apic_write(ioapic_base, i * 2 + 0x10, low); + io_apic_write(ioapic_base, i * 2 + 0x11, high); + + printk(BIOS_SPEW, "IOAPIC: reg 0x%08x value 0x%08x 0x%08x\n", + i, high, low); + } +} + +void setup_ioapic(void *ioapic_base, u8 ioapic_id) +{ + set_ioapic_id(ioapic_base, ioapic_id); + load_vectors(ioapic_base); +} diff --git a/src/arch/x86/lib/Makefile.inc b/src/arch/x86/lib/Makefile.inc deleted file mode 100644 index ccfe30ae67..0000000000 --- a/src/arch/x86/lib/Makefile.inc +++ /dev/null @@ -1,48 +0,0 @@ - -ifeq ($(CONFIG_ARCH_ROMSTAGE_X86_32)$(CONFIG_ARCH_ROMSTAGE_X86_64),y) - -romstage-y += cbfs_and_run.c -romstage-$(CONFIG_ARCH_RAMSTAGE_X86_32) += cpu_common.c -romstage-y += memset.c -romstage-y += memcpy.c -romstage-y += memmove.c -romstage-y += mmap_boot.c - -endif # CONFIG_ARCH_ROMSTAGE_X86_32 / CONFIG_ARCH_ROMSTAGE_X86_64 - -ifeq ($(CONFIG_ARCH_RAMSTAGE_X86_32)$(CONFIG_ARCH_RAMSTAGE_X86_64),y) - -ramstage-y += c_start.S -ramstage-y += cpu.c -ramstage-y += cpu_common.c -ramstage-y += pci_ops_conf1.c -ramstage-$(CONFIG_MMCONF_SUPPORT) += pci_ops_mmconf.c -ramstage-y += exception.c -ramstage-$(CONFIG_IOAPIC) += ioapic.c -ramstage-y += memset.c -ramstage-y += memcpy.c -ramstage-y += memmove.c -ramstage-y += ebda.c -ramstage-y += mmap_boot.c -ramstage-$(CONFIG_COOP_MULTITASKING) += thread.c -ramstage-$(CONFIG_COOP_MULTITASKING) += thread_switch.S -ramstage-$(CONFIG_COLLECT_TIMESTAMPS) += timestamp.c - -romstage-$(CONFIG_COLLECT_TIMESTAMPS) += timestamp.c - -smm-y += memset.c -smm-y += memcpy.c -smm-y += memmove.c -smm-y += mmap_boot.c - -ifeq ($(CONFIG_ARCH_RAMSTAGE_X86_32),y) -rmodules_x86_32-y += memset.c -rmodules_x86_32-y += memcpy.c -rmodules_x86_32-y += memmove.c -else -rmodules_x86_64-y += memset.c -rmodules_x86_64-y += memcpy.c -rmodules_x86_64-y += memmove.c -endif - -endif # CONFIG_ARCH_RAMSTAGE_X86_32 / CONFIG_ARCH_RAMSTAGE_X86_64 diff --git a/src/arch/x86/lib/c_start.S b/src/arch/x86/lib/c_start.S deleted file mode 100644 index 582966bfdc..0000000000 --- a/src/arch/x86/lib/c_start.S +++ /dev/null @@ -1,421 +0,0 @@ -#include - -/* Place the stack in the bss section. It's not necessary to define it in the - * the linker script. */ - .section .bss, "aw", @nobits -.global _stack -.global _estack - -.align CONFIG_STACK_SIZE -_stack: -.space CONFIG_MAX_CPUS*CONFIG_STACK_SIZE -_estack: -#if CONFIG_COOP_MULTITASKING -.global thread_stacks -thread_stacks: -.space CONFIG_STACK_SIZE*CONFIG_NUM_THREADS -#endif - - .section ".text._start", "ax", @progbits -#ifdef __x86_64__ - .code64 -#else - .code32 -#endif - .globl _start - .globl __rmodule_entry -__rmodule_entry: -_start: - cli - lgdt %cs:gdtaddr -#ifndef __x86_64__ - ljmp $0x10, $1f -#endif -1: movl $0x18, %eax - movl %eax, %ds - movl %eax, %es - movl %eax, %ss - movl %eax, %fs - movl %eax, %gs -#ifdef __x86_64__ - mov $0x48, %ecx - call SetCodeSelector -#endif - - post_code(POST_ENTRY_C_START) /* post 13 */ - - cld - - /** poison the stack. Code should not count on the - * stack being full of zeros. This stack poisoning - * recently uncovered a bug in the broadcast SIPI - * code. - */ - leal _stack, %edi - movl $_estack, %ecx - subl %edi, %ecx - shrl $2, %ecx /* it is 32 bit aligned, right? */ - movl $0xDEADBEEF, %eax - rep - stosl - - /* set new stack */ - movl $_estack, %esp - -#if CONFIG_COOP_MULTITASKING - /* Push the thread pointer. */ - push $0 -#endif - /* Push the cpu index and struct cpu */ - push $0 - push $0 - - /* Initialize the Interrupt Descriptor table */ - leal _idt, %edi - leal vec0, %ebx - movl $(0x10 << 16), %eax /* cs selector */ - -1: movw %bx, %ax - movl %ebx, %edx - movw $0x8E00, %dx /* Interrupt gate - dpl=0, present */ - movl %eax, 0(%edi) - movl %edx, 4(%edi) - addl $6, %ebx - addl $8, %edi - cmpl $_idt_end, %edi - jne 1b - - /* Load the Interrupt descriptor table */ -#ifndef __x86_64__ - lidt idtarg -#else - // FIXME port table to x64 - lidt idtarg -#endif - - /* - * Now we are finished. Memory is up, data is copied and - * bss is cleared. Now we call the main routine and - * let it do the rest. - */ - post_code(POST_PRE_HARDWAREMAIN) /* post fe */ - -#if CONFIG_GDB_WAIT - call gdb_hw_init - call gdb_stub_breakpoint -#endif - call main - /* NOTREACHED */ -.Lhlt: - post_code(POST_DEAD_CODE) /* post ee */ - hlt - jmp .Lhlt - -vec0: - push $0 /* error code */ - push $0 /* vector */ - jmp int_hand -vec1: - push $0 /* error code */ - push $1 /* vector */ - jmp int_hand - -vec2: - push $0 /* error code */ - push $2 /* vector */ - jmp int_hand - -vec3: - push $0 /* error code */ - push $3 /* vector */ - jmp int_hand - -vec4: - push $0 /* error code */ - push $4 /* vector */ - jmp int_hand - -vec5: - push $0 /* error code */ - push $5 /* vector */ - jmp int_hand - -vec6: - push $0 /* error code */ - push $6 /* vector */ - jmp int_hand - -vec7: - push $0 /* error code */ - push $7 /* vector */ - jmp int_hand - -vec8: - /* error code */ - push $8 /* vector */ - jmp int_hand - .word 0x9090 - -vec9: - push $0 /* error code */ - push $9 /* vector */ - jmp int_hand - -vec10: - /* error code */ - push $10 /* vector */ - jmp int_hand - .word 0x9090 - -vec11: - /* error code */ - push $11 /* vector */ - jmp int_hand - .word 0x9090 - -vec12: - /* error code */ - push $12 /* vector */ - jmp int_hand - .word 0x9090 - -vec13: - /* error code */ - push $13 /* vector */ - jmp int_hand - .word 0x9090 - -vec14: - /* error code */ - push $14 /* vector */ - jmp int_hand - .word 0x9090 - -vec15: - push $0 /* error code */ - push $15 /* vector */ - jmp int_hand - -vec16: - push $0 /* error code */ - push $16 /* vector */ - jmp int_hand - -vec17: - /* error code */ - push $17 /* vector */ - jmp int_hand - .word 0x9090 - -vec18: - push $0 /* error code */ - push $18 /* vector */ - jmp int_hand - -vec19: - push $0 /* error code */ - push $19 /* vector */ - jmp int_hand - -int_hand: - /* At this point, on x86-32, on the stack there is: - * 0(%esp) vector - * 4(%esp) error code - * 8(%esp) eip - * 12(%esp) cs - * 16(%esp) eflags - */ -#ifdef __x86_64__ - push %rdi - push %rsi - push %rbp - /* Original stack pointer */ - lea 32(%rsp), %rbp - push %rbp - push %rbx - push %rdx - push %rcx - push %rax - - push %rsp /* Pointer to structure on the stack */ - call x86_exception - pop %rax /* Drop the pointer */ - - pop %rax - pop %rcx - pop %rdx - pop %rbx - pop %rbp /* Ignore saved %rsp value */ - pop %rbp - pop %rsi - pop %rdi - - add $8, %rsp /* pop of the vector and error code */ -#else - pushl %edi - pushl %esi - pushl %ebp - - /* Original stack pointer */ - leal 32(%esp), %ebp - pushl %ebp - pushl %ebx - pushl %edx - pushl %ecx - pushl %eax - - pushl %esp /* Pointer to structure on the stack */ - call x86_exception - pop %eax /* Drop the pointer */ - - popl %eax - popl %ecx - popl %edx - popl %ebx - popl %ebp /* Ignore saved %esp value */ - popl %ebp - popl %esi - popl %edi - - addl $8, %esp /* pop of the vector and error code */ -#endif - - iret - -#if CONFIG_GDB_WAIT - - .globl gdb_stub_breakpoint -gdb_stub_breakpoint: -#ifdef __x86_64__ - pop %rax /* Return address */ - pushfl - push %cs - push %rax /* Return address */ - push $0 /* No error code */ - push $32 /* vector 32 is user defined */ -#else - popl %eax /* Return address */ - pushfl - pushl %cs - pushl %eax /* Return address */ - pushl $0 /* No error code */ - pushl $32 /* vector 32 is user defined */ -#endif - jmp int_hand -#endif - - .globl gdt, gdt_end, idtarg - -gdtaddr: - .word gdt_end - gdt - 1 -#ifdef __x86_64__ - .quad gdt -#else - .long gdt /* we know the offset */ -#endif - - .data - - /* This is the gdt for GCC part of coreboot. - * It is different from the gdt in ROMCC/ASM part of coreboot - * which is defined in entry32.inc - * - * When the machine is initially started, we use a very simple - * gdt from rom (that in entry32.inc) which only contains those - * entries we need for protected mode. - * - * When we're executing code from RAM, we want to do more complex - * stuff, like initializing PCI option roms in real mode, or doing - * a resume from a suspend to ram. - */ -gdt: - /* selgdt 0, unused */ - .word 0x0000, 0x0000 /* dummy */ - .byte 0x00, 0x00, 0x00, 0x00 - - /* selgdt 8, unused */ - .word 0x0000, 0x0000 /* dummy */ - .byte 0x00, 0x00, 0x00, 0x00 - - /* selgdt 0x10, flat code segment */ - .word 0xffff, 0x0000 - .byte 0x00, 0x9b, 0xcf, 0x00 /* G=1 and 0x0f, So we get 4Gbytes for limit */ - - /* selgdt 0x18, flat data segment */ - .word 0xffff, 0x0000 -#ifdef __x86_64__ - .byte 0x00, 0x92, 0xcf, 0x00 -#else - .byte 0x00, 0x93, 0xcf, 0x00 -#endif - - /* selgdt 0x20, unused */ - .word 0x0000, 0x0000 /* dummy */ - .byte 0x00, 0x00, 0x00, 0x00 - - /* The next two entries are used for executing VGA option ROMs */ - - /* selgdt 0x28 16 bit 64k code at 0x00000000 */ - .word 0xffff, 0x0000 - .byte 0, 0x9a, 0, 0 - - /* selgdt 0x30 16 bit 64k data at 0x00000000 */ - .word 0xffff, 0x0000 - .byte 0, 0x92, 0, 0 - - /* The next two entries are used for ACPI S3 RESUME */ - - /* selgdt 0x38, flat data segment 16 bit */ - .word 0x0000, 0x0000 /* dummy */ - .byte 0x00, 0x93, 0x8f, 0x00 /* G=1 and 0x0f, So we get 4Gbytes for limit */ - - /* selgdt 0x40, flat code segment 16 bit */ - .word 0xffff, 0x0000 - .byte 0x00, 0x9b, 0x8f, 0x00 /* G=1 and 0x0f, So we get 4Gbytes for limit */ - -#ifdef __x86_64__ - /* selgdt 0x48, flat x64 code segment */ - .word 0xffff, 0x0000 - .byte 0x00, 0x9b, 0xaf, 0x00 -#endif -gdt_end: - -idtarg: - .word _idt_end - _idt - 1 /* limit */ - .long _idt - .word 0 -_idt: - .fill 20, 8, 0 # idt is uninitialized -_idt_end: - -#ifdef __x86_64__ -SetCodeSelector: -.intel_syntax noprefix - - # save rsp because iret will align it to a 16 byte boundary - mov rdx, rsp - - # use iret to jump to a 64-bit offset in a new code segment - # iret will pop cs:rip, flags, then ss:rsp - mov ax, ss # need to push ss.. - push rax # push ss instuction not valid in x64 mode, so use ax - push rsp - pushfq - push rcx # cx is code segment selector from caller - mov rax, offset setCodeSelectorLongJump - push rax - - # the iret will continue at next instruction, with the new cs value loaded - iretq - -setCodeSelectorLongJump: - # restore rsp, it might not have been 16-byte aligned on entry - mov rsp, rdx - ret -.att_syntax prefix - - .previous -.code64 -#else - .previous -.code32 -#endif diff --git a/src/arch/x86/lib/cbfs_and_run.c b/src/arch/x86/lib/cbfs_and_run.c deleted file mode 100644 index b6d342623d..0000000000 --- a/src/arch/x86/lib/cbfs_and_run.c +++ /dev/null @@ -1,26 +0,0 @@ -/* - * This file is part of the coreboot project. - * - * Copyright (C) 2008-2009 coresystems GmbH - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation; version 2 of the License. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc. - */ - -#include -#include - -void asmlinkage copy_and_run(void) -{ - run_ramstage(); -} diff --git a/src/arch/x86/lib/cpu.c b/src/arch/x86/lib/cpu.c deleted file mode 100644 index 3eb7b9439e..0000000000 --- a/src/arch/x86/lib/cpu.c +++ /dev/null @@ -1,273 +0,0 @@ -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#ifndef __x86_64__ -/* Standard macro to see if a specific flag is changeable */ -static inline int flag_is_changeable_p(uint32_t flag) -{ - uint32_t f1, f2; - - asm( - "pushfl\n\t" - "pushfl\n\t" - "popl %0\n\t" - "movl %0,%1\n\t" - "xorl %2,%0\n\t" - "pushl %0\n\t" - "popfl\n\t" - "pushfl\n\t" - "popl %0\n\t" - "popfl\n\t" - : "=&r" (f1), "=&r" (f2) - : "ir" (flag)); - return ((f1^f2) & flag) != 0; -} - -/* - * Cyrix CPUs without cpuid or with cpuid not yet enabled can be detected - * by the fact that they preserve the flags across the division of 5/2. - * PII and PPro exhibit this behavior too, but they have cpuid available. - */ - -/* - * Perform the Cyrix 5/2 test. A Cyrix won't change - * the flags, while other 486 chips will. - */ -static inline int test_cyrix_52div(void) -{ - unsigned int test; - - __asm__ __volatile__( - "sahf\n\t" /* clear flags (%eax = 0x0005) */ - "div %b2\n\t" /* divide 5 by 2 */ - "lahf" /* store flags into %ah */ - : "=a" (test) - : "0" (5), "q" (2) - : "cc"); - - /* AH is 0x02 on Cyrix after the divide.. */ - return (unsigned char) (test >> 8) == 0x02; -} - -/* - * Detect a NexGen CPU running without BIOS hypercode new enough - * to have CPUID. (Thanks to Herbert Oppmann) - */ - -static int deep_magic_nexgen_probe(void) -{ - int ret; - - __asm__ __volatile__ ( - " movw $0x5555, %%ax\n" - " xorw %%dx,%%dx\n" - " movw $2, %%cx\n" - " divw %%cx\n" - " movl $0, %%eax\n" - " jnz 1f\n" - " movl $1, %%eax\n" - "1:\n" - : "=a" (ret) : : "cx", "dx" ); - return ret; -} -#endif - -/* List of cpu vendor strings along with their normalized - * id values. - */ -static struct { - int vendor; - const char *name; -} x86_vendors[] = { - { X86_VENDOR_INTEL, "GenuineIntel", }, - { X86_VENDOR_CYRIX, "CyrixInstead", }, - { X86_VENDOR_AMD, "AuthenticAMD", }, - { X86_VENDOR_UMC, "UMC UMC UMC ", }, - { X86_VENDOR_NEXGEN, "NexGenDriven", }, - { X86_VENDOR_CENTAUR, "CentaurHauls", }, - { X86_VENDOR_RISE, "RiseRiseRise", }, - { X86_VENDOR_TRANSMETA, "GenuineTMx86", }, - { X86_VENDOR_TRANSMETA, "TransmetaCPU", }, - { X86_VENDOR_NSC, "Geode by NSC", }, - { X86_VENDOR_SIS, "SiS SiS SiS ", }, -}; - -static const char *x86_vendor_name[] = { - [X86_VENDOR_INTEL] = "Intel", - [X86_VENDOR_CYRIX] = "Cyrix", - [X86_VENDOR_AMD] = "AMD", - [X86_VENDOR_UMC] = "UMC", - [X86_VENDOR_NEXGEN] = "NexGen", - [X86_VENDOR_CENTAUR] = "Centaur", - [X86_VENDOR_RISE] = "Rise", - [X86_VENDOR_TRANSMETA] = "Transmeta", - [X86_VENDOR_NSC] = "NSC", - [X86_VENDOR_SIS] = "SiS", -}; - -static const char *cpu_vendor_name(int vendor) -{ - const char *name; - name = ""; - if ((vendor < (ARRAY_SIZE(x86_vendor_name))) && - (x86_vendor_name[vendor] != 0)) - { - name = x86_vendor_name[vendor]; - } - return name; -} - -static void identify_cpu(struct device *cpu) -{ - char vendor_name[16]; - int i; - - vendor_name[0] = '\0'; /* Unset */ - -#ifndef __x86_64__ - /* Find the id and vendor_name */ - if (!cpu_have_cpuid()) { - /* Its a 486 if we can modify the AC flag */ - if (flag_is_changeable_p(X86_EFLAGS_AC)) { - cpu->device = 0x00000400; /* 486 */ - } else { - cpu->device = 0x00000300; /* 386 */ - } - if ((cpu->device == 0x00000400) && test_cyrix_52div()) { - memcpy(vendor_name, "CyrixInstead", 13); - /* If we ever care we can enable cpuid here */ - } - /* Detect NexGen with old hypercode */ - else if (deep_magic_nexgen_probe()) { - memcpy(vendor_name, "NexGenDriven", 13); - } - } -#endif - if (cpu_have_cpuid()) { - int cpuid_level; - struct cpuid_result result; - result = cpuid(0x00000000); - cpuid_level = result.eax; - vendor_name[ 0] = (result.ebx >> 0) & 0xff; - vendor_name[ 1] = (result.ebx >> 8) & 0xff; - vendor_name[ 2] = (result.ebx >> 16) & 0xff; - vendor_name[ 3] = (result.ebx >> 24) & 0xff; - vendor_name[ 4] = (result.edx >> 0) & 0xff; - vendor_name[ 5] = (result.edx >> 8) & 0xff; - vendor_name[ 6] = (result.edx >> 16) & 0xff; - vendor_name[ 7] = (result.edx >> 24) & 0xff; - vendor_name[ 8] = (result.ecx >> 0) & 0xff; - vendor_name[ 9] = (result.ecx >> 8) & 0xff; - vendor_name[10] = (result.ecx >> 16) & 0xff; - vendor_name[11] = (result.ecx >> 24) & 0xff; - vendor_name[12] = '\0'; - - /* Intel-defined flags: level 0x00000001 */ - if (cpuid_level >= 0x00000001) { - cpu->device = cpuid_eax(0x00000001); - } - else { - /* Have CPUID level 0 only unheard of */ - cpu->device = 0x00000400; - } - } - cpu->vendor = X86_VENDOR_UNKNOWN; - for(i = 0; i < ARRAY_SIZE(x86_vendors); i++) { - if (memcmp(vendor_name, x86_vendors[i].name, 12) == 0) { - cpu->vendor = x86_vendors[i].vendor; - break; - } - } -} - -struct cpu_driver *find_cpu_driver(struct device *cpu) -{ - struct cpu_driver *driver; - for (driver = cpu_drivers; driver < ecpu_drivers; driver++) { - struct cpu_device_id *id; - for (id = driver->id_table; - id->vendor != X86_VENDOR_INVALID; id++) { - if ((cpu->vendor == id->vendor) && - (cpu->device == id->device)) - { - return driver; - } - if (X86_VENDOR_ANY == id->vendor) - return driver; - } - } - return NULL; -} - -static void set_cpu_ops(struct device *cpu) -{ - struct cpu_driver *driver = find_cpu_driver(cpu); - cpu->ops = driver ? driver->ops : NULL; -} - -void cpu_initialize(unsigned int index) -{ - /* Because we busy wait at the printk spinlock. - * It is important to keep the number of printed messages - * from secondary cpus to a minimum, when debugging is - * disabled. - */ - struct device *cpu; - struct cpu_info *info; - struct cpuinfo_x86 c; - - info = cpu_info(); - - printk(BIOS_INFO, "Initializing CPU #%d\n", index); - - cpu = info->cpu; - if (!cpu) { - die("CPU: missing cpu device structure"); - } - - post_log_path(cpu); - - /* Find what type of cpu we are dealing with */ - identify_cpu(cpu); - printk(BIOS_DEBUG, "CPU: vendor %s device %x\n", - cpu_vendor_name(cpu->vendor), cpu->device); - - get_fms(&c, cpu->device); - - printk(BIOS_DEBUG, "CPU: family %02x, model %02x, stepping %02x\n", - c.x86, c.x86_model, c.x86_mask); - - /* Lookup the cpu's operations */ - set_cpu_ops(cpu); - - if(!cpu->ops) { - /* mask out the stepping and try again */ - cpu->device -= c.x86_mask; - set_cpu_ops(cpu); - cpu->device += c.x86_mask; - if(!cpu->ops) die("Unknown cpu"); - printk(BIOS_DEBUG, "Using generic cpu ops (good)\n"); - } - - - /* Initialize the cpu */ - if (cpu->ops && cpu->ops->init) { - cpu->enabled = 1; - cpu->initialized = 1; - cpu->ops->init(cpu); - } - post_log_clear(); - - printk(BIOS_INFO, "CPU #%d initialized\n", index); - - return; -} diff --git a/src/arch/x86/lib/cpu_common.c b/src/arch/x86/lib/cpu_common.c deleted file mode 100644 index af0ab2ae98..0000000000 --- a/src/arch/x86/lib/cpu_common.c +++ /dev/null @@ -1,65 +0,0 @@ -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#ifndef __x86_64__ -/* Standard macro to see if a specific flag is changeable */ -static inline int flag_is_changeable_p(uint32_t flag) -{ - uint32_t f1, f2; - - asm( - "pushfl\n\t" - "pushfl\n\t" - "popl %0\n\t" - "movl %0,%1\n\t" - "xorl %2,%0\n\t" - "pushl %0\n\t" - "popfl\n\t" - "pushfl\n\t" - "popl %0\n\t" - "popfl\n\t" - : "=&r" (f1), "=&r" (f2) - : "ir" (flag)); - return ((f1^f2) & flag) != 0; -} - -/* Probe for the CPUID instruction */ -int cpu_have_cpuid(void) -{ - return flag_is_changeable_p(X86_EFLAGS_ID); -} - -#else - -int cpu_have_cpuid(void) -{ - return 1; -} -#endif - -int cpu_cpuid_extended_level(void) -{ - return cpuid_eax(0x80000000); -} - -int cpu_phys_address_size(void) -{ - if (!(cpu_have_cpuid())) - return 32; - - if (cpu_cpuid_extended_level() >= 0x80000008) - return cpuid_eax(0x80000008) & 0xff; - - if (cpuid_edx(1) & (CPUID_FEATURE_PAE | CPUID_FEATURE_PSE36)) - return 36; - return 32; -} diff --git a/src/arch/x86/lib/ebda.c b/src/arch/x86/lib/ebda.c deleted file mode 100644 index 47dfbdb1e9..0000000000 --- a/src/arch/x86/lib/ebda.c +++ /dev/null @@ -1,52 +0,0 @@ -/* - * This file is part of the coreboot project. - * - * Copyright (C) 2012 The Chromium OS Authors. All rights reserved. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation; version 2 of - * the License. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc. - */ - -#include -#include -#include -#include -#include - -void setup_ebda(u32 low_memory_size, u16 ebda_segment, u16 ebda_size) -{ - /* Skip in S3 resume path */ - if (acpi_is_wakeup_s3()) - return; - - if (!low_memory_size || !ebda_segment || !ebda_size) - return; - - /* clear BIOS DATA AREA */ - memset((void *)X86_BDA_BASE, 0, X86_BDA_SIZE); - - write16(X86_EBDA_LOWMEM, (low_memory_size >> 10)); - write16(X86_EBDA_SEGMENT, ebda_segment); - - /* Set up EBDA */ - memset((void *)((uintptr_t)ebda_segment << 4), 0, ebda_size); - write16((void*)((uintptr_t)ebda_segment << 4), (ebda_size >> 10)); -} - -void setup_default_ebda(void) -{ - setup_ebda(DEFAULT_EBDA_LOWMEM, - DEFAULT_EBDA_SEGMENT, - DEFAULT_EBDA_SIZE); -} diff --git a/src/arch/x86/lib/exception.c b/src/arch/x86/lib/exception.c deleted file mode 100644 index 65181e224e..0000000000 --- a/src/arch/x86/lib/exception.c +++ /dev/null @@ -1,511 +0,0 @@ -#include -#include -#include - -#if CONFIG_GDB_STUB - -/* BUFMAX defines the maximum number of characters in inbound/outbound buffers. - * At least NUM_REGBYTES*2 are needed for register packets - */ -#define BUFMAX 400 -enum regnames { - EAX = 0, ECX, EDX, EBX, ESP, EBP, ESI, EDI, - PC /* also known as eip */, - PS /* also known as eflags */, - CS, SS, DS, ES, FS, GS, - NUM_REGS /* Number of registers. */ -}; - -static uint32_t gdb_stub_registers[NUM_REGS]; - -#define GDB_SIG0 0 /* Signal 0 */ -#define GDB_SIGHUP 1 /* Hangup */ -#define GDB_SIGINT 2 /* Interrupt */ -#define GDB_SIGQUIT 3 /* Quit */ -#define GDB_SIGILL 4 /* Illegal instruction */ -#define GDB_SIGTRAP 5 /* Trace/breakpoint trap */ -#define GDB_SIGABRT 6 /* Aborted */ -#define GDB_SIGEMT 7 /* Emulation trap */ -#define GDB_SIGFPE 8 /* Arithmetic exception */ -#define GDB_SIGKILL 9 /* Killed */ -#define GDB_SIGBUS 10 /* Bus error */ -#define GDB_SIGSEGV 11 /* Segmentation fault */ -#define GDB_SIGSYS 12 /* Bad system call */ -#define GDB_SIGPIPE 13 /* Broken pipe */ -#define GDB_SIGALRM 14 /* Alarm clock */ -#define GDB_SIGTERM 15 /* Terminated */ -#define GDB_SIGURG 16 /* Urgent I/O condition */ -#define GDB_SIGSTOP 17 /* Stopped (signal) */ -#define GDB_SIGTSTP 18 /* Stopped (user) */ -#define GDB_SIGCONT 19 /* Continued */ -#define GDB_SIGCHLD 20 /* Child status changed */ -#define GDB_SIGTTIN 21 /* Stopped (tty input) */ -#define GDB_SIGTTOU 22 /* Stopped (tty output) */ -#define GDB_SIGIO 23 /* I/O possible */ -#define GDB_SIGXCPU 24 /* CPU time limit exceeded */ -#define GDB_SIGXFSZ 25 /* File size limit exceeded */ -#define GDB_SIGVTALRM 26 /* Virtual timer expired */ -#define GDB_SIGPROF 27 /* Profiling timer expired */ -#define GDB_SIGWINCH 28 /* Window size changed */ -#define GDB_SIGLOST 29 /* Resource lost */ -#define GDB_SIGUSR1 30 /* User defined signal 1 */ -#define GDB_SUGUSR2 31 /* User defined signal 2 */ -#define GDB_SIGPWR 32 /* Power fail/restart */ -#define GDB_SIGPOLL 33 /* Pollable event occurred */ -#define GDB_SIGWIND 34 /* SIGWIND */ -#define GDB_SIGPHONE 35 /* SIGPHONE */ -#define GDB_SIGWAITING 36 /* Process's LWPs are blocked */ -#define GDB_SIGLWP 37 /* Signal LWP */ -#define GDB_SIGDANGER 38 /* Swap space dangerously low */ -#define GDB_SIGGRANT 39 /* Monitor mode granted */ -#define GDB_SIGRETRACT 40 /* Need to relinquish monitor mode */ -#define GDB_SIGMSG 41 /* Monitor mode data available */ -#define GDB_SIGSOUND 42 /* Sound completed */ -#define GDB_SIGSAK 43 /* Secure attention */ -#define GDB_SIGPRIO 44 /* SIGPRIO */ - -#define GDB_SIG33 45 /* Real-time event 33 */ -#define GDB_SIG34 46 /* Real-time event 34 */ -#define GDB_SIG35 47 /* Real-time event 35 */ -#define GDB_SIG36 48 /* Real-time event 36 */ -#define GDB_SIG37 49 /* Real-time event 37 */ -#define GDB_SIG38 50 /* Real-time event 38 */ -#define GDB_SIG39 51 /* Real-time event 39 */ -#define GDB_SIG40 52 /* Real-time event 40 */ -#define GDB_SIG41 53 /* Real-time event 41 */ -#define GDB_SIG42 54 /* Real-time event 42 */ -#define GDB_SIG43 55 /* Real-time event 43 */ -#define GDB_SIG44 56 /* Real-time event 44 */ -#define GDB_SIG45 57 /* Real-time event 45 */ -#define GDB_SIG46 58 /* Real-time event 46 */ -#define GDB_SIG47 59 /* Real-time event 47 */ -#define GDB_SIG48 60 /* Real-time event 48 */ -#define GDB_SIG49 61 /* Real-time event 49 */ -#define GDB_SIG50 62 /* Real-time event 50 */ -#define GDB_SIG51 63 /* Real-time event 51 */ -#define GDB_SIG52 64 /* Real-time event 52 */ -#define GDB_SIG53 65 /* Real-time event 53 */ -#define GDB_SIG54 66 /* Real-time event 54 */ -#define GDB_SIG55 67 /* Real-time event 55 */ -#define GDB_SIG56 68 /* Real-time event 56 */ -#define GDB_SIG57 69 /* Real-time event 57 */ -#define GDB_SIG58 70 /* Real-time event 58 */ -#define GDB_SIG59 71 /* Real-time event 59 */ -#define GDB_SIG60 72 /* Real-time event 60 */ -#define GDB_SIG61 73 /* Real-time event 61 */ -#define GDB_SIG62 74 /* Real-time event 62 */ -#define GDB_SIG63 75 /* Real-time event 63 */ -#define GDB_SIGCANCEL 76 /* LWP internal signal */ -#define GDB_SIG32 77 /* Real-time event 32 */ -#define GDB_SIG64 78 /* Real-time event 64 */ -#define GDB_SIG65 79 /* Real-time event 65 */ -#define GDB_SIG66 80 /* Real-time event 66 */ -#define GDB_SIG67 81 /* Real-time event 67 */ -#define GDB_SIG68 82 /* Real-time event 68 */ -#define GDB_SIG69 83 /* Real-time event 69 */ -#define GDB_SIG70 84 /* Real-time event 70 */ -#define GDB_SIG71 85 /* Real-time event 71 */ -#define GDB_SIG72 86 /* Real-time event 72 */ -#define GDB_SIG73 87 /* Real-time event 73 */ -#define GDB_SIG74 88 /* Real-time event 74 */ -#define GDB_SIG75 89 /* Real-time event 75 */ -#define GDB_SIG76 90 /* Real-time event 76 */ -#define GDB_SIG77 91 /* Real-time event 77 */ -#define GDB_SIG78 92 /* Real-time event 78 */ -#define GDB_SIG79 93 /* Real-time event 79 */ -#define GDB_SIG80 94 /* Real-time event 80 */ -#define GDB_SIG81 95 /* Real-time event 81 */ -#define GDB_SIG82 96 /* Real-time event 82 */ -#define GDB_SIG83 97 /* Real-time event 83 */ -#define GDB_SIG84 98 /* Real-time event 84 */ -#define GDB_SIG85 99 /* Real-time event 85 */ -#define GDB_SIG86 100 /* Real-time event 86 */ -#define GDB_SIG87 101 /* Real-time event 87 */ -#define GDB_SIG88 102 /* Real-time event 88 */ -#define GDB_SIG89 103 /* Real-time event 89 */ -#define GDB_SIG90 104 /* Real-time event 90 */ -#define GDB_SIG91 105 /* Real-time event 91 */ -#define GDB_SIG92 106 /* Real-time event 92 */ -#define GDB_SIG93 107 /* Real-time event 93 */ -#define GDB_SIG94 108 /* Real-time event 94 */ -#define GDB_SIG95 109 /* Real-time event 95 */ -#define GDB_SIG96 110 /* Real-time event 96 */ -#define GDB_SIG97 111 /* Real-time event 97 */ -#define GDB_SIG98 112 /* Real-time event 98 */ -#define GDB_SIG99 113 /* Real-time event 99 */ -#define GDB_SIG100 114 /* Real-time event 100 */ -#define GDB_SIG101 115 /* Real-time event 101 */ -#define GDB_SIG102 116 /* Real-time event 102 */ -#define GDB_SIG103 117 /* Real-time event 103 */ -#define GDB_SIG104 118 /* Real-time event 104 */ -#define GDB_SIG105 119 /* Real-time event 105 */ -#define GDB_SIG106 120 /* Real-time event 106 */ -#define GDB_SIG107 121 /* Real-time event 107 */ -#define GDB_SIG108 122 /* Real-time event 108 */ -#define GDB_SIG109 123 /* Real-time event 109 */ -#define GDB_SIG110 124 /* Real-time event 110 */ -#define GDB_SIG111 125 /* Real-time event 111 */ -#define GDB_SIG112 126 /* Real-time event 112 */ -#define GDB_SIG113 127 /* Real-time event 113 */ -#define GDB_SIG114 128 /* Real-time event 114 */ -#define GDB_SIG115 129 /* Real-time event 115 */ -#define GDB_SIG116 130 /* Real-time event 116 */ -#define GDB_SIG117 131 /* Real-time event 117 */ -#define GDB_SIG118 132 /* Real-time event 118 */ -#define GDB_SIG119 133 /* Real-time event 119 */ -#define GDB_SIG120 134 /* Real-time event 120 */ -#define GDB_SIG121 135 /* Real-time event 121 */ -#define GDB_SIG122 136 /* Real-time event 122 */ -#define GDB_SIG123 137 /* Real-time event 123 */ -#define GDB_SIG124 138 /* Real-time event 124 */ -#define GDB_SIG125 139 /* Real-time event 125 */ -#define GDB_SIG126 140 /* Real-time event 126 */ -#define GDB_SIG127 141 /* Real-time event 127 */ -#define GDB_SIGINFO 142 /* Information request */ -#define GDB_UNKNOWN 143 /* Unknown signal */ -#define GDB_DEFAULT 144 /* error: default signal */ -/* Mach exceptions */ -#define GDB_EXC_BAD_ACCESS 145 /* Could not access memory */ -#define GDB_EXC_BAD_INSTRCTION 146 /* Illegal instruction/operand */ -#define GDB_EXC_ARITHMETIC 147 /* Arithmetic exception */ -#define GDB_EXC_EMULATION 148 /* Emulation instruction */ -#define GDB_EXC_SOFTWARE 149 /* Software generated exception */ -#define GDB_EXC_BREAKPOINT 150 /* Breakpoint */ - - - -static unsigned char exception_to_signal[] = -{ - [0] = GDB_SIGFPE, /* divide by zero */ - [1] = GDB_SIGTRAP, /* debug exception */ - [2] = GDB_SIGSEGV, /* NMI Interrupt */ - [3] = GDB_SIGTRAP, /* Breakpoint */ - [4] = GDB_SIGSEGV, /* into instruction (overflow) */ - [5] = GDB_SIGSEGV, /* bound instruction */ - [6] = GDB_SIGILL, /* Invalid opcode */ - [7] = GDB_SIGSEGV, /* coprocessor not available */ - [8] = GDB_SIGSEGV, /* double fault */ - [9] = GDB_SIGFPE, /* coprocessor segment overrun */ - [10] = GDB_SIGSEGV, /* Invalid TSS */ - [11] = GDB_SIGBUS, /* Segment not present */ - [12] = GDB_SIGBUS, /* stack exception */ - [13] = GDB_SIGSEGV, /* general protection */ - [14] = GDB_SIGSEGV, /* page fault */ - [15] = GDB_UNKNOWN, /* reserved */ - [16] = GDB_SIGEMT, /* coprocessor error */ - [17] = GDB_SIGBUS, /* alignment check */ - [18] = GDB_SIGSEGV, /* machine check */ - [19] = GDB_SIGFPE, /* simd floating point exception */ - [20] = GDB_UNKNOWN, - [21] = GDB_UNKNOWN, - [22] = GDB_UNKNOWN, - [23] = GDB_UNKNOWN, - [24] = GDB_UNKNOWN, - [25] = GDB_UNKNOWN, - [26] = GDB_UNKNOWN, - [27] = GDB_UNKNOWN, - [28] = GDB_UNKNOWN, - [29] = GDB_UNKNOWN, - [30] = GDB_UNKNOWN, - [31] = GDB_UNKNOWN, - [32] = GDB_SIGINT, /* User interrupt */ -}; - -static const char hexchars[] = "0123456789abcdef"; -static char in_buffer[BUFMAX]; -static char out_buffer[BUFMAX]; - - -static inline void stub_putc(int ch) -{ - gdb_tx_byte(ch); -} - -static inline void stub_flush(void) -{ - gdb_tx_flush(); -} - -static inline int stub_getc(void) -{ - return gdb_rx_byte(); -} - -static int hex(char ch) -{ - if ((ch >= 'a') && (ch <= 'f')) - return (ch - 'a' + 10); - if ((ch >= '0') && (ch <= '9')) - return (ch - '0'); - if ((ch >= 'A') && (ch <= 'F')) - return (ch - 'A' + 10); - return (-1); -} - -/* - * While we find hexadecimal digits, build an int. - * Fals is returned if nothing is parsed true otherwise. - */ -static int parse_ulong(char **ptr, unsigned long *value) -{ - int digit; - char *start; - - start = *ptr; - *value = 0; - - while((digit = hex(**ptr)) >= 0) { - *value = ((*value) << 4) | digit; - (*ptr)++; - } - return start != *ptr; -} - -/* convert the memory pointed to by mem into hex, placing result in buf */ -/* return a pointer to the last char put in buf (null) */ -static void copy_to_hex(char *buf, void *addr, unsigned long count) -{ - unsigned char ch; - char *mem = addr; - - while(count--) { - ch = *mem++; - *buf++ = hexchars[ch >> 4]; - *buf++ = hexchars[ch & 0x0f]; - } - *buf = 0; - return; -} - - -/* convert the hex array pointed to by buf into binary to be placed in mem */ -/* return a pointer to the character AFTER the last byte written */ -static void copy_from_hex(void *addr, char *buf, unsigned long count) -{ - unsigned char ch; - char *mem = addr; - - while(count--) { - ch = hex (*buf++) << 4; - ch = ch + hex (*buf++); - *mem++ = ch; - } -} - - -/* scan for the sequence $# */ - -static int get_packet(char *buffer) -{ - unsigned char checksum; - unsigned char xmitcsum; - int count; - char ch; - - /* Wishlit implement a timeout in get_packet */ - do { - /* wait around for the start character, ignore all other characters */ - while ((ch = (stub_getc() & 0x7f)) != '$'); - checksum = 0; - xmitcsum = -1; - - count = 0; - - /* now, read until a # or end of buffer is found */ - while (count < BUFMAX) { - ch = stub_getc() & 0x7f; - if (ch == '#') - break; - checksum = checksum + ch; - buffer[count] = ch; - count = count + 1; - } - buffer[count] = 0; - - if (ch == '#') { - xmitcsum = hex(stub_getc() & 0x7f) << 4; - xmitcsum += hex(stub_getc() & 0x7f); - - if (checksum != xmitcsum) { - stub_putc('-'); /* failed checksum */ - stub_flush(); - } - else { - stub_putc('+'); /* successful transfer */ - stub_flush(); - } - } - } while(checksum != xmitcsum); - return 1; -} - -/* send the packet in buffer.*/ -static void put_packet(char *buffer) -{ - unsigned char checksum; - int count; - char ch; - - /* $#. */ - do { - stub_putc('$'); - checksum = 0; - count = 0; - - while ((ch = buffer[count])) { - stub_putc(ch); - checksum += ch; - count += 1; - } - - stub_putc('#'); - stub_putc(hexchars[checksum >> 4]); - stub_putc(hexchars[checksum % 16]); - stub_flush(); - - } while ((stub_getc() & 0x7f) != '+'); - -} -#endif /* CONFIG_GDB_STUB */ - -#include - -void x86_exception(struct eregs *info); - -void x86_exception(struct eregs *info) -{ -#if CONFIG_GDB_STUB - int signo; - memcpy(gdb_stub_registers, info, 8*sizeof(uint32_t)); - gdb_stub_registers[PC] = info->eip; - gdb_stub_registers[CS] = info->cs; - gdb_stub_registers[PS] = info->eflags; - signo = GDB_UNKNOWN; - if (info->vector < ARRAY_SIZE(exception_to_signal)) { - signo = exception_to_signal[info->vector]; - } - - /* reply to the host that an exception has occured */ - out_buffer[0] = 'S'; - out_buffer[1] = hexchars[(signo>>4) & 0xf]; - out_buffer[2] = hexchars[signo & 0xf]; - out_buffer[3] = '\0'; - put_packet(out_buffer); - - while(1) { - unsigned long addr, length; - char *ptr; - out_buffer[0] = '\0'; - out_buffer[1] = '\0'; - if (!get_packet(in_buffer)) { - break; - } - switch(in_buffer[0]) { - case '?': /* last signal */ - out_buffer[0] = 'S'; - out_buffer[1] = hexchars[(signo >> 4) & 0xf]; - out_buffer[2] = hexchars[signo & 0xf]; - out_buffer[3] = '\0'; - break; - case 'g': /* return the value of the cpu registers */ - copy_to_hex(out_buffer, &gdb_stub_registers, sizeof(gdb_stub_registers)); - break; - case 'G': /* set the value of the CPU registers - return OK */ - copy_from_hex(&gdb_stub_registers, in_buffer + 1, sizeof(gdb_stub_registers)); - memcpy(info, gdb_stub_registers, 8*sizeof(uint32_t)); - info->eip = gdb_stub_registers[PC]; - info->cs = gdb_stub_registers[CS]; - info->eflags = gdb_stub_registers[PS]; - memcpy(out_buffer, "OK",3); - break; - case 'm': - /* mAA..AA,LLLL Read LLLL bytes at address AA..AA */ - ptr = &in_buffer[1]; - if ( parse_ulong(&ptr, &addr) && - (*ptr++ == ',') && - parse_ulong(&ptr, &length)) { - copy_to_hex(out_buffer, (void *)addr, length); - } else { - memcpy(out_buffer, "E01", 4); - } - break; - case 'M': - /* MAA..AA,LLLL: Write LLLL bytes at address AA.AA return OK */ - ptr = &in_buffer[1]; - if ( parse_ulong(&ptr, &addr) && - (*(ptr++) == ',') && - parse_ulong(&ptr, &length) && - (*(ptr++) == ':')) { - copy_from_hex((void *)addr, ptr, length); - memcpy(out_buffer, "OK", 3); - } - else { - memcpy(out_buffer, "E02", 4); - } - break; - case 's': - case 'c': - /* cAA..AA Continue at address AA..AA(optional) */ - /* sAA..AA Step one instruction from AA..AA(optional) */ - ptr = &in_buffer[1]; - if (parse_ulong(&ptr, &addr)) { - info->eip = addr; - } - - /* Clear the trace bit */ - info->eflags &= ~(1 << 8); - /* Set the trace bit if we are single stepping */ - if (in_buffer[0] == 's') { - info->eflags |= (1 << 8); - } - return; - break; - case 'D': - memcpy(out_buffer, "OK", 3); - break; - case 'k': /* kill request? */ - break; - case 'q': /* query */ - break; - case 'z': /* z0AAAA,LLLL remove memory breakpoint */ - /* z1AAAA,LLLL remove hardware breakpoint */ - /* z2AAAA,LLLL remove write watchpoint */ - /* z3AAAA,LLLL remove read watchpoint */ - /* z4AAAA,LLLL remove access watchpoint */ - case 'Z': /* Z0AAAA,LLLL insert memory breakpoint */ - /* Z1AAAA,LLLL insert hardware breakpoint */ - /* Z2AAAA,LLLL insert write watchpoint */ - /* Z3AAAA,LLLL insert read watchpoint */ - /* Z4AAAA,LLLL insert access watchpoint */ - break; - default: - break; - } - put_packet(out_buffer); - } -#else /* !CONFIG_GDB_STUB */ -#define MDUMP_SIZE 0x80 - printk(BIOS_EMERG, - "Unexpected Exception: %d @ %02x:%08x - Halting\n" - "Code: %d eflags: %08x\n" - "eax: %08x ebx: %08x ecx: %08x edx: %08x\n" - "edi: %08x esi: %08x ebp: %08x esp: %08x\n", - info->vector, info->cs, info->eip, - info->error_code, info->eflags, - info->eax, info->ebx, info->ecx, info->edx, - info->edi, info->esi, info->ebp, info->esp); - u8 *code = (u8*)((uintptr_t)info->eip - (MDUMP_SIZE >>1)); - /* Align to 8-byte boundary please, and print eight bytes per row. - * This is done to make DRAM burst timing/reordering errors more - * evident from the looking at the dump */ - code = (u8*)((uintptr_t)code & ~0x7); - int i; - for(i = 0; i < MDUMP_SIZE; i++) - { - if( (i & 0x07) == 0 ) - printk(BIOS_EMERG, "\n%p:\t", code + i); - printk(BIOS_EMERG, "%.2x ", code[i]); - } - die(""); -#endif -} diff --git a/src/arch/x86/lib/id.inc b/src/arch/x86/lib/id.inc deleted file mode 100644 index f8aba0b946..0000000000 --- a/src/arch/x86/lib/id.inc +++ /dev/null @@ -1,18 +0,0 @@ - .section ".id", "a", @progbits - - .globl __id_start -__id_start: -ver: - .asciz COREBOOT_VERSION -vendor: - .asciz CONFIG_MAINBOARD_VENDOR -part: - .asciz CONFIG_MAINBOARD_PART_NUMBER -.long __id_end + CONFIG_ID_SECTION_OFFSET - ver /* Reverse offset to the vendor id */ -.long __id_end + CONFIG_ID_SECTION_OFFSET - vendor /* Reverse offset to the vendor id */ -.long __id_end + CONFIG_ID_SECTION_OFFSET - part /* Reverse offset to the part number */ -.long CONFIG_ROM_SIZE /* Size of this romimage */ - .globl __id_end - -__id_end: -.previous diff --git a/src/arch/x86/lib/id.ld b/src/arch/x86/lib/id.ld deleted file mode 100644 index cfd091dc17..0000000000 --- a/src/arch/x86/lib/id.ld +++ /dev/null @@ -1,6 +0,0 @@ -SECTIONS { - . = (0xffffffff - CONFIG_ID_SECTION_OFFSET) - (__id_end - __id_start) + 1; - .id (.): { - *(.id) - } -} diff --git a/src/arch/x86/lib/ioapic.c b/src/arch/x86/lib/ioapic.c deleted file mode 100644 index 1b131278fd..0000000000 --- a/src/arch/x86/lib/ioapic.c +++ /dev/null @@ -1,153 +0,0 @@ -/* - * This file is part of the coreboot project. - * - * Copyright (C) 2010 coresystems GmbH - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; version 2 of the License. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc. - */ - -#include -#include -#include -#include - -u32 io_apic_read(void *ioapic_base, u32 reg) -{ - write32(ioapic_base, reg); - return read32(ioapic_base + 0x10); -} - -void io_apic_write(void *ioapic_base, u32 reg, u32 value) -{ - write32(ioapic_base, reg); - write32(ioapic_base + 0x10, value); -} - -static int ioapic_interrupt_count(void *ioapic_base) -{ - /* Read the available number of interrupts. */ - int ioapic_interrupts = (io_apic_read(ioapic_base, 0x01) >> 16) & 0xff; - if (ioapic_interrupts == 0xff) - ioapic_interrupts = 23; - ioapic_interrupts += 1; /* Bits 23-16 specify the maximum redirection - entry, which is the number of interrupts - minus 1. */ - printk(BIOS_DEBUG, "IOAPIC: %d interrupts\n", ioapic_interrupts); - - return ioapic_interrupts; -} - -void clear_ioapic(void *ioapic_base) -{ - u32 low, high; - u32 i, ioapic_interrupts; - - printk(BIOS_DEBUG, "IOAPIC: Clearing IOAPIC at %p\n", ioapic_base); - - ioapic_interrupts = ioapic_interrupt_count(ioapic_base); - - low = DISABLED; - high = NONE; - - for (i = 0; i < ioapic_interrupts; i++) { - io_apic_write(ioapic_base, i * 2 + 0x10, low); - io_apic_write(ioapic_base, i * 2 + 0x11, high); - - printk(BIOS_SPEW, "IOAPIC: reg 0x%08x value 0x%08x 0x%08x\n", - i, high, low); - } - - if (io_apic_read(ioapic_base, 0x10) == 0xffffffff) { - printk(BIOS_WARNING, "IOAPIC not responding.\n"); - return; - } -} - -void set_ioapic_id(void *ioapic_base, u8 ioapic_id) -{ - u32 bsp_lapicid = lapicid(); - int i; - - printk(BIOS_DEBUG, "IOAPIC: Initializing IOAPIC at 0x%p\n", - ioapic_base); - printk(BIOS_DEBUG, "IOAPIC: Bootstrap Processor Local APIC = 0x%02x\n", - bsp_lapicid); - - if (ioapic_id) { - printk(BIOS_DEBUG, "IOAPIC: ID = 0x%02x\n", ioapic_id); - /* Set IOAPIC ID if it has been specified. */ - io_apic_write(ioapic_base, 0x00, - (io_apic_read(ioapic_base, 0x00) & 0xf0ffffff) | - (ioapic_id << 24)); - } - - printk(BIOS_SPEW, "IOAPIC: Dumping registers\n"); - for (i = 0; i < 3; i++) - printk(BIOS_SPEW, " reg 0x%04x: 0x%08x\n", i, - io_apic_read(ioapic_base, i)); - -} - -static void load_vectors(void *ioapic_base) -{ - u32 bsp_lapicid = lapicid(); - u32 low, high; - u32 i, ioapic_interrupts; - - ioapic_interrupts = ioapic_interrupt_count(ioapic_base); - -#if CONFIG_IOAPIC_INTERRUPTS_ON_FSB - /* - * For the Pentium 4 and above APICs deliver their interrupts - * on the front side bus, enable that. - */ - printk(BIOS_DEBUG, "IOAPIC: Enabling interrupts on FSB\n"); - io_apic_write(ioapic_base, 0x03, - io_apic_read(ioapic_base, 0x03) | (1 << 0)); -#endif -#if CONFIG_IOAPIC_INTERRUPTS_ON_APIC_SERIAL_BUS - printk(BIOS_DEBUG, "IOAPIC: Enabling interrupts on APIC serial bus\n"); - io_apic_write(ioapic_base, 0x03, 0); -#endif - - /* Enable Virtual Wire Mode. */ - low = ENABLED | TRIGGER_EDGE | POLARITY_HIGH | PHYSICAL_DEST | ExtINT; - high = bsp_lapicid << (56 - 32); - - io_apic_write(ioapic_base, 0x10, low); - io_apic_write(ioapic_base, 0x11, high); - - if (io_apic_read(ioapic_base, 0x10) == 0xffffffff) { - printk(BIOS_WARNING, "IOAPIC not responding.\n"); - return; - } - - printk(BIOS_SPEW, "IOAPIC: reg 0x%08x value 0x%08x 0x%08x\n", - 0, high, low); - low = DISABLED; - high = NONE; - for (i = 1; i < ioapic_interrupts; i++) { - io_apic_write(ioapic_base, i * 2 + 0x10, low); - io_apic_write(ioapic_base, i * 2 + 0x11, high); - - printk(BIOS_SPEW, "IOAPIC: reg 0x%08x value 0x%08x 0x%08x\n", - i, high, low); - } -} - -void setup_ioapic(void *ioapic_base, u8 ioapic_id) -{ - set_ioapic_id(ioapic_base, ioapic_id); - load_vectors(ioapic_base); -} diff --git a/src/arch/x86/lib/memcpy.c b/src/arch/x86/lib/memcpy.c deleted file mode 100644 index 4915a9eb51..0000000000 --- a/src/arch/x86/lib/memcpy.c +++ /dev/null @@ -1,22 +0,0 @@ -#include - -void *memcpy(void *dest, const void *src, size_t n) -{ - unsigned long d0, d1, d2; - - asm volatile( -#ifdef __x86_64__ - "rep ; movsd\n\t" - "mov %4,%%rcx\n\t" -#else - "rep ; movsl\n\t" - "movl %4,%%ecx\n\t" -#endif - "rep ; movsb\n\t" - : "=&c" (d0), "=&D" (d1), "=&S" (d2) - : "0" (n >> 2), "g" (n & 3), "1" (dest), "2" (src) - : "memory" - ); - - return dest; -} diff --git a/src/arch/x86/lib/memmove.c b/src/arch/x86/lib/memmove.c deleted file mode 100644 index ba121278da..0000000000 --- a/src/arch/x86/lib/memmove.c +++ /dev/null @@ -1,187 +0,0 @@ -#include - -void *memmove(void *dest, const void *src, size_t n) -{ - int d0,d1,d2,d3,d4,d5; - char *ret = dest; - - __asm__ __volatile__( - /* Handle more 16bytes in loop */ - "cmp $0x10, %0\n\t" - "jb 1f\n\t" - - /* Decide forward/backward copy mode */ - "cmp %2, %1\n\t" - "jb 2f\n\t" - - /* - * movs instruction have many startup latency - * so we handle small size by general register. - */ - "cmp $680, %0\n\t" - "jb 3f\n\t" - /* - * movs instruction is only good for aligned case. - */ - "mov %1, %3\n\t" - "xor %2, %3\n\t" - "and $0xff, %3\n\t" - "jz 4f\n\t" - "3:\n\t" - "sub $0x10, %0\n\t" - - /* - * We gobble 16byts forward in each loop. - */ - "3:\n\t" - "sub $0x10, %0\n\t" - "mov 0*4(%1), %3\n\t" - "mov 1*4(%1), %4\n\t" - "mov %3, 0*4(%2)\n\t" - "mov %4, 1*4(%2)\n\t" - "mov 2*4(%1), %3\n\t" - "mov 3*4(%1), %4\n\t" - "mov %3, 2*4(%2)\n\t" - "mov %4, 3*4(%2)\n\t" - "lea 0x10(%1), %1\n\t" - "lea 0x10(%2), %2\n\t" - "jae 3b\n\t" - "add $0x10, %0\n\t" - "jmp 1f\n\t" - - /* - * Handle data forward by movs. - */ - ".p2align 4\n\t" - "4:\n\t" - "mov -4(%1, %0), %3\n\t" - "lea -4(%2, %0), %4\n\t" - "shr $2, %0\n\t" - "rep movsl\n\t" - "mov %3, (%4)\n\t" - "jmp 11f\n\t" - /* - * Handle data backward by movs. - */ - ".p2align 4\n\t" - "6:\n\t" - "mov (%1), %3\n\t" - "mov %2, %4\n\t" - "lea -4(%1, %0), %1\n\t" - "lea -4(%2, %0), %2\n\t" - "shr $2, %0\n\t" - "std\n\t" - "rep movsl\n\t" - "mov %3,(%4)\n\t" - "cld\n\t" - "jmp 11f\n\t" - - /* - * Start to prepare for backward copy. - */ - ".p2align 4\n\t" - "2:\n\t" - "cmp $680, %0\n\t" - "jb 5f\n\t" - "mov %1, %3\n\t" - "xor %2, %3\n\t" - "and $0xff, %3\n\t" - "jz 6b\n\t" - - /* - * Calculate copy position to tail. - */ - "5:\n\t" - "add %0, %1\n\t" - "add %0, %2\n\t" - "sub $0x10, %0\n\t" - - /* - * We gobble 16byts backward in each loop. - */ - "7:\n\t" - "sub $0x10, %0\n\t" - - "mov -1*4(%1), %3\n\t" - "mov -2*4(%1), %4\n\t" - "mov %3, -1*4(%2)\n\t" - "mov %4, -2*4(%2)\n\t" - "mov -3*4(%1), %3\n\t" - "mov -4*4(%1), %4\n\t" - "mov %3, -3*4(%2)\n\t" - "mov %4, -4*4(%2)\n\t" - "lea -0x10(%1), %1\n\t" - "lea -0x10(%2), %2\n\t" - "jae 7b\n\t" - /* - * Calculate copy position to head. - */ - "add $0x10, %0\n\t" - "sub %0, %1\n\t" - "sub %0, %2\n\t" - - /* - * Move data from 8 bytes to 15 bytes. - */ - ".p2align 4\n\t" - "1:\n\t" - "cmp $8, %0\n\t" - "jb 8f\n\t" - "mov 0*4(%1), %3\n\t" - "mov 1*4(%1), %4\n\t" - "mov -2*4(%1, %0), %5\n\t" - "mov -1*4(%1, %0), %1\n\t" - - "mov %3, 0*4(%2)\n\t" - "mov %4, 1*4(%2)\n\t" - "mov %5, -2*4(%2, %0)\n\t" - "mov %1, -1*4(%2, %0)\n\t" - "jmp 11f\n\t" - - /* - * Move data from 4 bytes to 7 bytes. - */ - ".p2align 4\n\t" - "8:\n\t" - "cmp $4, %0\n\t" - "jb 9f\n\t" - "mov 0*4(%1), %3\n\t" - "mov -1*4(%1, %0), %4\n\t" - "mov %3, 0*4(%2)\n\t" - "mov %4, -1*4(%2, %0)\n\t" - "jmp 11f\n\t" - - /* - * Move data from 2 bytes to 3 bytes. - */ - ".p2align 4\n\t" - "9:\n\t" - "cmp $2, %0\n\t" - "jb 10f\n\t" - "movw 0*2(%1), %%dx\n\t" - "movw -1*2(%1, %0), %%bx\n\t" - "movw %%dx, 0*2(%2)\n\t" - "movw %%bx, -1*2(%2, %0)\n\t" - "jmp 11f\n\t" - - /* - * Move data for 1 byte. - */ - ".p2align 4\n\t" - "10:\n\t" - "cmp $1, %0\n\t" - "jb 11f\n\t" - "movb (%1), %%cl\n\t" - "movb %%cl, (%2)\n\t" - ".p2align 4\n\t" - "11:" - : "=&c" (d0), "=&S" (d1), "=&D" (d2), - "=r" (d3),"=r" (d4), "=r"(d5) - :"0" (n), - "1" (src), - "2" (dest) - :"memory"); - - return ret; - -} diff --git a/src/arch/x86/lib/memset.c b/src/arch/x86/lib/memset.c deleted file mode 100644 index d534556fd9..0000000000 --- a/src/arch/x86/lib/memset.c +++ /dev/null @@ -1,84 +0,0 @@ -/* - * Copyright (C) 1991,1992,1993,1997,1998,2003, 2005 Free Software Foundation, Inc. - * This file is part of the GNU C Library. - * - * See file CREDITS for list of people who contributed to this - * project. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation; either version 2 of - * the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc. - */ - -/* From glibc-2.14, sysdeps/i386/memset.c */ - -#include -#include - -typedef uint32_t op_t; - -void *memset(void *dstpp, int c, size_t len) -{ - int d0; - unsigned long int dstp = (unsigned long int) dstpp; - - /* This explicit register allocation improves code very much indeed. */ - register op_t x asm("ax"); - - x = (unsigned char) c; - - /* Clear the direction flag, so filling will move forward. */ - asm volatile("cld"); - - /* This threshold value is optimal. */ - if (len >= 12) { - /* Fill X with four copies of the char we want to fill with. */ - x |= (x << 8); - x |= (x << 16); - - /* Adjust LEN for the bytes handled in the first loop. */ - len -= (-dstp) % sizeof(op_t); - - /* - * There are at least some bytes to set. No need to test for - * LEN == 0 in this alignment loop. - */ - - /* Fill bytes until DSTP is aligned on a longword boundary. */ - asm volatile( - "rep\n" - "stosb" /* %0, %2, %3 */ : - "=D" (dstp), "=c" (d0) : - "0" (dstp), "1" ((-dstp) % sizeof(op_t)), "a" (x) : - "memory"); - - /* Fill longwords. */ - asm volatile( - "rep\n" - "stosl" /* %0, %2, %3 */ : - "=D" (dstp), "=c" (d0) : - "0" (dstp), "1" (len / sizeof(op_t)), "a" (x) : - "memory"); - len %= sizeof(op_t); - } - - /* Write the last few bytes. */ - asm volatile( - "rep\n" - "stosb" /* %0, %2, %3 */ : - "=D" (dstp), "=c" (d0) : - "0" (dstp), "1" (len), "a" (x) : - "memory"); - - return dstpp; -} diff --git a/src/arch/x86/lib/mmap_boot.c b/src/arch/x86/lib/mmap_boot.c deleted file mode 100644 index 4dd269b772..0000000000 --- a/src/arch/x86/lib/mmap_boot.c +++ /dev/null @@ -1,75 +0,0 @@ -/* - * This file is part of the coreboot project. - * - * Copyright 2015 Google Inc. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; version 2 of the License. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc. - */ - -#include -#include -#include -#include -#include - -/* The ROM is memory mapped just below 4GiB. Form a pointer for the base. */ -#define rom_base ((void *)(uintptr_t)(-(int32_t)CONFIG_ROM_SIZE)) - -static const struct mem_region_device boot_dev = - MEM_REGION_DEV_INIT(rom_base, CONFIG_ROM_SIZE); - -const struct region_device *boot_device_ro(void) -{ - return &boot_dev.rdev; -} - -int cbfs_boot_region_properties(struct cbfs_props *props) -{ - struct cbfs_header header; - int32_t offset; - const struct region_device *bdev; - - bdev = boot_device_ro(); - - rdev_readat(bdev, &offset, CONFIG_ROM_SIZE - sizeof(offset), - sizeof(offset)); - - /* The offset is relative to the end of the media. */ - offset += CONFIG_ROM_SIZE; - - rdev_readat(bdev, &header , offset, sizeof(header)); - - header.magic = ntohl(header.magic); - header.romsize = ntohl(header.romsize); - header.bootblocksize = ntohl(header.bootblocksize); - header.align = ntohl(header.align); - header.offset = ntohl(header.offset); - - if (header.magic != CBFS_HEADER_MAGIC) - return -1; - - props->align = header.align; - props->offset = header.offset; - if (CONFIG_ROM_SIZE != header.romsize) - props->size = CONFIG_ROM_SIZE; - else - props->size = header.romsize; - props->size -= props->offset; - props->size -= header.bootblocksize; - props->size = ALIGN_DOWN(props->size, props->align); - - printk(BIOS_DEBUG, "CBFS @ %zx size %zx\n", props->offset, props->size); - - return 0; -} diff --git a/src/arch/x86/lib/pci_ops_conf1.c b/src/arch/x86/lib/pci_ops_conf1.c deleted file mode 100644 index 77df4b314f..0000000000 --- a/src/arch/x86/lib/pci_ops_conf1.c +++ /dev/null @@ -1,71 +0,0 @@ -#include -#include -#include -#include -#include -#include -/* - * Functions for accessing PCI configuration space with type 1 accesses - */ - -#if !CONFIG_PCI_IO_CFG_EXT -#define CONFIG_CMD(bus,devfn, where) (0x80000000 | (bus << 16) | \ - (devfn << 8) | (where & ~3)) -#else -#define CONFIG_CMD(bus,devfn, where) (0x80000000 | (bus << 16) | \ - (devfn << 8) | ((where & 0xff) & ~3) |\ - ((where & 0xf00)<<16)) -#endif - -static uint8_t pci_conf1_read_config8(struct bus *pbus, int bus, int devfn, - int where) -{ - outl(CONFIG_CMD(bus, devfn, where), 0xCF8); - return inb(0xCFC + (where & 3)); -} - -static uint16_t pci_conf1_read_config16(struct bus *pbus, int bus, int devfn, - int where) -{ - outl(CONFIG_CMD(bus, devfn, where), 0xCF8); - return inw(0xCFC + (where & 2)); -} - -static uint32_t pci_conf1_read_config32(struct bus *pbus, int bus, int devfn, - int where) -{ - outl(CONFIG_CMD(bus, devfn, where), 0xCF8); - return inl(0xCFC); -} - -static void pci_conf1_write_config8(struct bus *pbus, int bus, int devfn, - int where, uint8_t value) -{ - outl(CONFIG_CMD(bus, devfn, where), 0xCF8); - outb(value, 0xCFC + (where & 3)); -} - -static void pci_conf1_write_config16(struct bus *pbus, int bus, int devfn, - int where, uint16_t value) -{ - outl(CONFIG_CMD(bus, devfn, where), 0xCF8); - outw(value, 0xCFC + (where & 2)); -} - -static void pci_conf1_write_config32(struct bus *pbus, int bus, int devfn, - int where, uint32_t value) -{ - outl(CONFIG_CMD(bus, devfn, where), 0xCF8); - outl(value, 0xCFC); -} - -#undef CONFIG_CMD - -const struct pci_bus_operations pci_cf8_conf1 = { - .read8 = pci_conf1_read_config8, - .read16 = pci_conf1_read_config16, - .read32 = pci_conf1_read_config32, - .write8 = pci_conf1_write_config8, - .write16 = pci_conf1_write_config16, - .write32 = pci_conf1_write_config32, -}; diff --git a/src/arch/x86/lib/pci_ops_mmconf.c b/src/arch/x86/lib/pci_ops_mmconf.c deleted file mode 100644 index e4fa128551..0000000000 --- a/src/arch/x86/lib/pci_ops_mmconf.c +++ /dev/null @@ -1,61 +0,0 @@ -#include -#include -#include -#include -#include -#include - -/* - * Functions for accessing PCI configuration space with mmconf accesses - */ - -#define PCI_MMIO_ADDR(SEGBUS, DEVFN, WHERE, MASK) \ - ((void *)(((uintptr_t)CONFIG_MMCONF_BASE_ADDRESS |\ - (((SEGBUS) & 0xFFF) << 20) |\ - (((DEVFN) & 0xFF) << 12) |\ - ((WHERE) & 0xFFF)) & ~MASK)) - -static uint8_t pci_mmconf_read_config8(struct bus *pbus, int bus, int devfn, - int where) -{ - return read8(PCI_MMIO_ADDR(bus, devfn, where, 0)); -} - -static uint16_t pci_mmconf_read_config16(struct bus *pbus, int bus, int devfn, - int where) -{ - return read16(PCI_MMIO_ADDR(bus, devfn, where, 1)); -} - -static uint32_t pci_mmconf_read_config32(struct bus *pbus, int bus, int devfn, - int where) -{ - return read32(PCI_MMIO_ADDR(bus, devfn, where, 3)); -} - -static void pci_mmconf_write_config8(struct bus *pbus, int bus, int devfn, - int where, uint8_t value) -{ - write8(PCI_MMIO_ADDR(bus, devfn, where, 0), value); -} - -static void pci_mmconf_write_config16(struct bus *pbus, int bus, int devfn, - int where, uint16_t value) -{ - write16(PCI_MMIO_ADDR(bus, devfn, where, 1), value); -} - -static void pci_mmconf_write_config32(struct bus *pbus, int bus, int devfn, - int where, uint32_t value) -{ - write32(PCI_MMIO_ADDR(bus, devfn, where, 3), value); -} - -const struct pci_bus_operations pci_ops_mmconf = { - .read8 = pci_mmconf_read_config8, - .read16 = pci_mmconf_read_config16, - .read32 = pci_mmconf_read_config32, - .write8 = pci_mmconf_write_config8, - .write16 = pci_mmconf_write_config16, - .write32 = pci_mmconf_write_config32, -}; diff --git a/src/arch/x86/lib/romcc_console.c b/src/arch/x86/lib/romcc_console.c deleted file mode 100644 index bfc35bc74c..0000000000 --- a/src/arch/x86/lib/romcc_console.c +++ /dev/null @@ -1,87 +0,0 @@ -/* - * This file is part of the coreboot project. - * - * Copyright (C) 2003 Eric Biederman - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; version 2 of the License. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc. - */ - -#include -#include -#include -#include - -/* Include the sources. */ -#if CONFIG_CONSOLE_SERIAL && CONFIG_DRIVERS_UART_8250IO -#include "drivers/uart/util.c" -#include "drivers/uart/uart8250io.c" -#endif -#if CONFIG_CONSOLE_NE2K -#include "drivers/net/ne2k.c" -#endif - -void console_hw_init(void) -{ -#if CONFIG_CONSOLE_SERIAL - uart_init(CONFIG_UART_FOR_CONSOLE); -#endif -#if CONFIG_CONSOLE_NE2K - ne2k_init(CONFIG_CONSOLE_NE2K_IO_PORT); -#endif -} - -void console_tx_byte(unsigned char byte) -{ -#if CONFIG_CONSOLE_SERIAL - uart_tx_byte(CONFIG_UART_FOR_CONSOLE, byte); -#endif -#if CONFIG_CONSOLE_NE2K - ne2k_append_data_byte(byte, CONFIG_CONSOLE_NE2K_IO_PORT); -#endif -} - -void console_tx_flush(void) -{ -#if CONFIG_CONSOLE_SERIAL - uart_tx_flush(CONFIG_UART_FOR_CONSOLE); -#endif -#if CONFIG_CONSOLE_NE2K - ne2k_transmit(CONFIG_CONSOLE_NE2K_IO_PORT); -#endif -} - -#include -#include -#include - -void console_init(void) -{ - static const char console_test[] = - "\n\ncoreboot-" - COREBOOT_VERSION - COREBOOT_EXTRA_VERSION - " " - COREBOOT_BUILD - " romstage starting...\n"; - - console_hw_init(); - - print_info(console_test); -} - -void die(const char *msg) -{ - print_emerg(msg); - halt(); -} diff --git a/src/arch/x86/lib/stages.c b/src/arch/x86/lib/stages.c deleted file mode 100644 index c06abe6793..0000000000 --- a/src/arch/x86/lib/stages.c +++ /dev/null @@ -1,25 +0,0 @@ -/* - * This file is part of the coreboot project. - * - * Copyright (C) 2010 coresystems GmbH - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation; version 2 of the License. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc. - */ - -static void skip_romstage(void) -{ - asm volatile ( - "jmp __main\n" - ); -} diff --git a/src/arch/x86/lib/thread.c b/src/arch/x86/lib/thread.c deleted file mode 100644 index f81a2d20ca..0000000000 --- a/src/arch/x86/lib/thread.c +++ /dev/null @@ -1,65 +0,0 @@ -/* - * This file is part of the coreboot project. - * - * Copyright (C) 2013 Google, Inc. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; version 2 of the License. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc. - */ - -#include - -/* The stack frame looks like the following after a pushad instruction. */ -struct pushad_regs { - uint32_t edi; /* Offset 0x00 */ - uint32_t esi; /* Offset 0x04 */ - uint32_t ebp; /* Offset 0x08 */ - uint32_t esp; /* Offset 0x0c */ - uint32_t ebx; /* Offset 0x10 */ - uint32_t edx; /* Offset 0x14 */ - uint32_t ecx; /* Offset 0x18 */ - uint32_t eax; /* Offset 0x1c */ -}; - -static inline uintptr_t push_stack(uintptr_t cur_stack, uintptr_t value) -{ - uintptr_t *addr; - - cur_stack -= sizeof(value); - addr = (uintptr_t *)cur_stack; - *addr = value; - return cur_stack; -} - -void arch_prepare_thread(struct thread *t, - void asmlinkage (*thread_entry)(void *), void *arg) -{ - uintptr_t stack = t->stack_current; - - /* Imitate thread_entry(t) with return address of 0. thread_entry() - * is assumed to never return. */ - stack = push_stack(stack, (uintptr_t)arg); - stack = push_stack(stack, (uintptr_t)0); - stack = push_stack(stack, (uintptr_t)thread_entry); - /* Make room for the registers. Ignore intial values. */ - stack -= sizeof(struct pushad_regs); - - t->stack_current = stack; -} - -void *arch_get_thread_stackbase(void) -{ - /* defined in c_start.S */ - extern u8 thread_stacks[]; - return &thread_stacks[0]; -} diff --git a/src/arch/x86/lib/thread_switch.S b/src/arch/x86/lib/thread_switch.S deleted file mode 100644 index 52d4d3094b..0000000000 --- a/src/arch/x86/lib/thread_switch.S +++ /dev/null @@ -1,58 +0,0 @@ -/* - * This file is part of the coreboot project. - * - * Copyright (C) 2013 Google, Inc. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; version 2 of the License. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc. - */ -.code32 -.text - -/* - * stack layout after pushad: - * +------------+ - * | save stack | <-- esp + 0x28 - * +------------+ - * | new stack | <-- esp + 0x24 - * +------------+ - * | ret addr | <-- esp + 0x20 - * +------------+ - * | eax | <-- esp + 0x1c - * +------------+ - * | ecx | <-- esp + 0x18 - * +------------+ - * | edx | <-- esp + 0x14 - * +------------+ - * | ebx | <-- esp + 0x10 - * +------------+ - * | orig esp | <-- esp + 0x0c - * +------------+ - * | ebp | <-- esp + 0x08 - * +------------+ - * | esi | <-- esp + 0x04 - * +------------+ - * | edi | <-- esp + 0x00 - * +------------+ - */ -.globl switch_to_thread -switch_to_thread: - pusha - /* Save the current stack */ - movl 0x28(%esp), %ebx - movl %esp, (%ebx) - /* Switch to the new stack. */ - movl 0x24(%esp), %eax - movl %eax, %esp - popa - ret diff --git a/src/arch/x86/lib/timestamp.c b/src/arch/x86/lib/timestamp.c deleted file mode 100644 index 9df505a570..0000000000 --- a/src/arch/x86/lib/timestamp.c +++ /dev/null @@ -1,26 +0,0 @@ -/* - * This file is part of the coreboot project. - * - * Copyright 2013 Google Inc. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; version 2 of the License. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc. - */ - -#include -#include - -uint64_t timestamp_get(void) -{ - return rdtscll(); -} diff --git a/src/arch/x86/lib/walkcbfs.S b/src/arch/x86/lib/walkcbfs.S deleted file mode 100644 index 60eb8b53b0..0000000000 --- a/src/arch/x86/lib/walkcbfs.S +++ /dev/null @@ -1,117 +0,0 @@ -#define CBFS_HEADER_PTR 0xfffffffc - -#define CBFS_HEADER_MAGIC 0 -#define CBFS_HEADER_VERSION (CBFS_HEADER_MAGIC + 4) -#define CBFS_HEADER_ROMSIZE (CBFS_HEADER_VERSION + 4) -#define CBFS_HEADER_BOOTBLOCKSIZE (CBFS_HEADER_ROMSIZE + 4) -#define CBFS_HEADER_ALIGN (CBFS_HEADER_BOOTBLOCKSIZE + 4) -#define CBFS_HEADER_OFFSET (CBFS_HEADER_ALIGN + 4) - -#define CBFS_FILE_MAGIC 0 -#define CBFS_FILE_LEN (CBFS_FILE_MAGIC + 8) -#define CBFS_FILE_TYPE (CBFS_FILE_LEN + 4) -#define CBFS_FILE_CHECKSUM (CBFS_FILE_TYPE + 4) -#define CBFS_FILE_OFFSET (CBFS_FILE_CHECKSUM + 4) - -#define CBFS_FILE_STRUCTSIZE (CBFS_FILE_OFFSET + 4) - -/* - * input %esi: filename - * input %esp: return address (not pointer to return address!) - * output %eax: pointer to CBFS header - * clobbers %ebx, %ecx, %edi - */ -walkcbfs_asm: - cld - - mov CBFS_HEADER_PTR, %eax - mov CBFS_HEADER_ROMSIZE(%eax), %ecx - bswap %ecx - mov $0, %ebx - sub %ecx, %ebx /* rom base address in ebx */ - mov CBFS_HEADER_OFFSET(%eax), %ecx - bswap %ecx - add %ecx, %ebx /* address where we start looking for LARCHIVEs */ - - /* determine filename length */ - mov $0, %eax -1: - cmpb $0, (%eax,%esi) - jz 2f - add $1, %eax - jmp 1b -2: - add $1, %eax -walker: - mov 0(%ebx), %edi /* Check for LARCHIVE header */ - cmp %edi, filemagic - jne searchfile - mov 4(%ebx), %edi - cmp %edi, filemagic+4 - jne searchfile - - /* LARCHIVE header found */ - mov %ebx, %edi - add $CBFS_FILE_STRUCTSIZE, %edi /* edi = address of first byte after struct cbfs_file */ - mov %eax, %ecx - repe cmpsb - /* zero flag set if strings are equal */ - jnz tryharder - - /* we found it! */ - mov %ebx, %eax - jmp *%esp - -tryharder: - sub %ebx, %edi - sub $CBFS_FILE_STRUCTSIZE, %edi /* edi = # of walked bytes */ - sub %edi, %esi /* esi = start of filename */ - - /* ebx = ecx = (current+offset+len+ALIGN-1) & ~(ALIGN-1) */ - mov CBFS_FILE_OFFSET(%ebx), %ecx - bswap %ecx - add %ebx, %ecx - mov CBFS_FILE_LEN(%ebx), %edi - bswap %edi - add %edi, %ecx - mov CBFS_HEADER_PTR, %edi - mov CBFS_HEADER_ALIGN(%edi), %edi - bswap %edi - sub $1, %edi - add %edi, %ecx - not %edi - and %edi, %ecx - - /* if oldaddr >= addr, leave */ - cmp %ebx, %ecx - jbe out - - mov %ecx, %ebx - -check_for_exit: - /* look if we should exit: did we pass into the bootblock already? */ - mov CBFS_HEADER_PTR, %ecx - mov CBFS_HEADER_BOOTBLOCKSIZE(%ecx), %ecx - bswap %ecx - not %ecx - add $1, %ecx - - cmp %ecx, %ebx - /* if bootblockstart >= addr (==we're still in the data area) , jump back */ - jbe walker - -out: - mov $0, %eax - jmp *%esp - - -searchfile: - /* if filemagic isn't found, move forward cbfs_header->align bytes */ - mov CBFS_HEADER_PTR, %edi - mov CBFS_HEADER_ALIGN(%edi), %edi - bswap %edi - add %edi, %ebx - jmp check_for_exit - -filemagic: - .ascii "LARCHIVE" diff --git a/src/arch/x86/memcpy.c b/src/arch/x86/memcpy.c new file mode 100644 index 0000000000..4915a9eb51 --- /dev/null +++ b/src/arch/x86/memcpy.c @@ -0,0 +1,22 @@ +#include + +void *memcpy(void *dest, const void *src, size_t n) +{ + unsigned long d0, d1, d2; + + asm volatile( +#ifdef __x86_64__ + "rep ; movsd\n\t" + "mov %4,%%rcx\n\t" +#else + "rep ; movsl\n\t" + "movl %4,%%ecx\n\t" +#endif + "rep ; movsb\n\t" + : "=&c" (d0), "=&D" (d1), "=&S" (d2) + : "0" (n >> 2), "g" (n & 3), "1" (dest), "2" (src) + : "memory" + ); + + return dest; +} diff --git a/src/arch/x86/memmove.c b/src/arch/x86/memmove.c new file mode 100644 index 0000000000..ba121278da --- /dev/null +++ b/src/arch/x86/memmove.c @@ -0,0 +1,187 @@ +#include + +void *memmove(void *dest, const void *src, size_t n) +{ + int d0,d1,d2,d3,d4,d5; + char *ret = dest; + + __asm__ __volatile__( + /* Handle more 16bytes in loop */ + "cmp $0x10, %0\n\t" + "jb 1f\n\t" + + /* Decide forward/backward copy mode */ + "cmp %2, %1\n\t" + "jb 2f\n\t" + + /* + * movs instruction have many startup latency + * so we handle small size by general register. + */ + "cmp $680, %0\n\t" + "jb 3f\n\t" + /* + * movs instruction is only good for aligned case. + */ + "mov %1, %3\n\t" + "xor %2, %3\n\t" + "and $0xff, %3\n\t" + "jz 4f\n\t" + "3:\n\t" + "sub $0x10, %0\n\t" + + /* + * We gobble 16byts forward in each loop. + */ + "3:\n\t" + "sub $0x10, %0\n\t" + "mov 0*4(%1), %3\n\t" + "mov 1*4(%1), %4\n\t" + "mov %3, 0*4(%2)\n\t" + "mov %4, 1*4(%2)\n\t" + "mov 2*4(%1), %3\n\t" + "mov 3*4(%1), %4\n\t" + "mov %3, 2*4(%2)\n\t" + "mov %4, 3*4(%2)\n\t" + "lea 0x10(%1), %1\n\t" + "lea 0x10(%2), %2\n\t" + "jae 3b\n\t" + "add $0x10, %0\n\t" + "jmp 1f\n\t" + + /* + * Handle data forward by movs. + */ + ".p2align 4\n\t" + "4:\n\t" + "mov -4(%1, %0), %3\n\t" + "lea -4(%2, %0), %4\n\t" + "shr $2, %0\n\t" + "rep movsl\n\t" + "mov %3, (%4)\n\t" + "jmp 11f\n\t" + /* + * Handle data backward by movs. + */ + ".p2align 4\n\t" + "6:\n\t" + "mov (%1), %3\n\t" + "mov %2, %4\n\t" + "lea -4(%1, %0), %1\n\t" + "lea -4(%2, %0), %2\n\t" + "shr $2, %0\n\t" + "std\n\t" + "rep movsl\n\t" + "mov %3,(%4)\n\t" + "cld\n\t" + "jmp 11f\n\t" + + /* + * Start to prepare for backward copy. + */ + ".p2align 4\n\t" + "2:\n\t" + "cmp $680, %0\n\t" + "jb 5f\n\t" + "mov %1, %3\n\t" + "xor %2, %3\n\t" + "and $0xff, %3\n\t" + "jz 6b\n\t" + + /* + * Calculate copy position to tail. + */ + "5:\n\t" + "add %0, %1\n\t" + "add %0, %2\n\t" + "sub $0x10, %0\n\t" + + /* + * We gobble 16byts backward in each loop. + */ + "7:\n\t" + "sub $0x10, %0\n\t" + + "mov -1*4(%1), %3\n\t" + "mov -2*4(%1), %4\n\t" + "mov %3, -1*4(%2)\n\t" + "mov %4, -2*4(%2)\n\t" + "mov -3*4(%1), %3\n\t" + "mov -4*4(%1), %4\n\t" + "mov %3, -3*4(%2)\n\t" + "mov %4, -4*4(%2)\n\t" + "lea -0x10(%1), %1\n\t" + "lea -0x10(%2), %2\n\t" + "jae 7b\n\t" + /* + * Calculate copy position to head. + */ + "add $0x10, %0\n\t" + "sub %0, %1\n\t" + "sub %0, %2\n\t" + + /* + * Move data from 8 bytes to 15 bytes. + */ + ".p2align 4\n\t" + "1:\n\t" + "cmp $8, %0\n\t" + "jb 8f\n\t" + "mov 0*4(%1), %3\n\t" + "mov 1*4(%1), %4\n\t" + "mov -2*4(%1, %0), %5\n\t" + "mov -1*4(%1, %0), %1\n\t" + + "mov %3, 0*4(%2)\n\t" + "mov %4, 1*4(%2)\n\t" + "mov %5, -2*4(%2, %0)\n\t" + "mov %1, -1*4(%2, %0)\n\t" + "jmp 11f\n\t" + + /* + * Move data from 4 bytes to 7 bytes. + */ + ".p2align 4\n\t" + "8:\n\t" + "cmp $4, %0\n\t" + "jb 9f\n\t" + "mov 0*4(%1), %3\n\t" + "mov -1*4(%1, %0), %4\n\t" + "mov %3, 0*4(%2)\n\t" + "mov %4, -1*4(%2, %0)\n\t" + "jmp 11f\n\t" + + /* + * Move data from 2 bytes to 3 bytes. + */ + ".p2align 4\n\t" + "9:\n\t" + "cmp $2, %0\n\t" + "jb 10f\n\t" + "movw 0*2(%1), %%dx\n\t" + "movw -1*2(%1, %0), %%bx\n\t" + "movw %%dx, 0*2(%2)\n\t" + "movw %%bx, -1*2(%2, %0)\n\t" + "jmp 11f\n\t" + + /* + * Move data for 1 byte. + */ + ".p2align 4\n\t" + "10:\n\t" + "cmp $1, %0\n\t" + "jb 11f\n\t" + "movb (%1), %%cl\n\t" + "movb %%cl, (%2)\n\t" + ".p2align 4\n\t" + "11:" + : "=&c" (d0), "=&S" (d1), "=&D" (d2), + "=r" (d3),"=r" (d4), "=r"(d5) + :"0" (n), + "1" (src), + "2" (dest) + :"memory"); + + return ret; + +} diff --git a/src/arch/x86/memset.c b/src/arch/x86/memset.c new file mode 100644 index 0000000000..d534556fd9 --- /dev/null +++ b/src/arch/x86/memset.c @@ -0,0 +1,84 @@ +/* + * Copyright (C) 1991,1992,1993,1997,1998,2003, 2005 Free Software Foundation, Inc. + * This file is part of the GNU C Library. + * + * See file CREDITS for list of people who contributed to this + * project. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc. + */ + +/* From glibc-2.14, sysdeps/i386/memset.c */ + +#include +#include + +typedef uint32_t op_t; + +void *memset(void *dstpp, int c, size_t len) +{ + int d0; + unsigned long int dstp = (unsigned long int) dstpp; + + /* This explicit register allocation improves code very much indeed. */ + register op_t x asm("ax"); + + x = (unsigned char) c; + + /* Clear the direction flag, so filling will move forward. */ + asm volatile("cld"); + + /* This threshold value is optimal. */ + if (len >= 12) { + /* Fill X with four copies of the char we want to fill with. */ + x |= (x << 8); + x |= (x << 16); + + /* Adjust LEN for the bytes handled in the first loop. */ + len -= (-dstp) % sizeof(op_t); + + /* + * There are at least some bytes to set. No need to test for + * LEN == 0 in this alignment loop. + */ + + /* Fill bytes until DSTP is aligned on a longword boundary. */ + asm volatile( + "rep\n" + "stosb" /* %0, %2, %3 */ : + "=D" (dstp), "=c" (d0) : + "0" (dstp), "1" ((-dstp) % sizeof(op_t)), "a" (x) : + "memory"); + + /* Fill longwords. */ + asm volatile( + "rep\n" + "stosl" /* %0, %2, %3 */ : + "=D" (dstp), "=c" (d0) : + "0" (dstp), "1" (len / sizeof(op_t)), "a" (x) : + "memory"); + len %= sizeof(op_t); + } + + /* Write the last few bytes. */ + asm volatile( + "rep\n" + "stosb" /* %0, %2, %3 */ : + "=D" (dstp), "=c" (d0) : + "0" (dstp), "1" (len), "a" (x) : + "memory"); + + return dstpp; +} diff --git a/src/arch/x86/mmap_boot.c b/src/arch/x86/mmap_boot.c new file mode 100644 index 0000000000..4dd269b772 --- /dev/null +++ b/src/arch/x86/mmap_boot.c @@ -0,0 +1,75 @@ +/* + * This file is part of the coreboot project. + * + * Copyright 2015 Google Inc. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; version 2 of the License. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc. + */ + +#include +#include +#include +#include +#include + +/* The ROM is memory mapped just below 4GiB. Form a pointer for the base. */ +#define rom_base ((void *)(uintptr_t)(-(int32_t)CONFIG_ROM_SIZE)) + +static const struct mem_region_device boot_dev = + MEM_REGION_DEV_INIT(rom_base, CONFIG_ROM_SIZE); + +const struct region_device *boot_device_ro(void) +{ + return &boot_dev.rdev; +} + +int cbfs_boot_region_properties(struct cbfs_props *props) +{ + struct cbfs_header header; + int32_t offset; + const struct region_device *bdev; + + bdev = boot_device_ro(); + + rdev_readat(bdev, &offset, CONFIG_ROM_SIZE - sizeof(offset), + sizeof(offset)); + + /* The offset is relative to the end of the media. */ + offset += CONFIG_ROM_SIZE; + + rdev_readat(bdev, &header , offset, sizeof(header)); + + header.magic = ntohl(header.magic); + header.romsize = ntohl(header.romsize); + header.bootblocksize = ntohl(header.bootblocksize); + header.align = ntohl(header.align); + header.offset = ntohl(header.offset); + + if (header.magic != CBFS_HEADER_MAGIC) + return -1; + + props->align = header.align; + props->offset = header.offset; + if (CONFIG_ROM_SIZE != header.romsize) + props->size = CONFIG_ROM_SIZE; + else + props->size = header.romsize; + props->size -= props->offset; + props->size -= header.bootblocksize; + props->size = ALIGN_DOWN(props->size, props->align); + + printk(BIOS_DEBUG, "CBFS @ %zx size %zx\n", props->offset, props->size); + + return 0; +} diff --git a/src/arch/x86/mpspec.c b/src/arch/x86/mpspec.c new file mode 100644 index 0000000000..1a0ac31fd0 --- /dev/null +++ b/src/arch/x86/mpspec.c @@ -0,0 +1,597 @@ +/* + * This file is part of the coreboot project. + * + * Copyright (C) 2014 Sage Electronic Engineering, LLC. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; version 2 of the License. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/* Initialize the specified "mc" struct with initial values. */ +void mptable_init(struct mp_config_table *mc, u32 lapic_addr) +{ + int i; + + memset(mc, 0, sizeof(*mc)); + + memcpy(mc->mpc_signature, MPC_SIGNATURE, 4); + + mc->mpc_length = sizeof(*mc); /* Initially just the header size. */ + mc->mpc_spec = 0x04; /* MultiProcessor specification 1.4 */ + mc->mpc_checksum = 0; /* Not yet computed. */ + mc->mpc_oemptr = 0; + mc->mpc_oemsize = 0; + mc->mpc_entry_count = 0; /* No entries yet... */ + mc->mpc_lapic = lapic_addr; + mc->mpe_length = 0; + mc->mpe_checksum = 0; + mc->reserved = 0; + + strncpy(mc->mpc_oem, CONFIG_MAINBOARD_VENDOR, 8); + strncpy(mc->mpc_productid, CONFIG_MAINBOARD_PART_NUMBER, 12); + + /* + * The oem/productid fields are exactly 8/12 bytes long. If the resp. + * entry is shorter, the remaining bytes are filled with spaces. + */ + for (i = MIN(strlen(CONFIG_MAINBOARD_VENDOR), 8); i < 8; i++) + mc->mpc_oem[i] = ' '; + for (i = MIN(strlen(CONFIG_MAINBOARD_PART_NUMBER), 12); i < 12; i++) + mc->mpc_productid[i] = ' '; +} + +static unsigned char smp_compute_checksum(void *v, int len) +{ + unsigned char *bytes; + unsigned char checksum; + int i; + bytes = v; + checksum = 0; + for(i = 0; i < len; i++) { + checksum -= bytes[i]; + } + return checksum; +} + +static void *smp_write_floating_table_physaddr(uintptr_t addr, uintptr_t mpf_physptr, unsigned int virtualwire) +{ + struct intel_mp_floating *mf; + void *v; + + v = (void *)addr; + mf = v; + mf->mpf_signature[0] = '_'; + mf->mpf_signature[1] = 'M'; + mf->mpf_signature[2] = 'P'; + mf->mpf_signature[3] = '_'; + mf->mpf_physptr = mpf_physptr; + mf->mpf_length = 1; + mf->mpf_specification = 4; + mf->mpf_checksum = 0; + mf->mpf_feature1 = 0; + mf->mpf_feature2 = virtualwire?MP_FEATURE_PIC:MP_FEATURE_VIRTUALWIRE; + mf->mpf_feature3 = 0; + mf->mpf_feature4 = 0; + mf->mpf_feature5 = 0; + mf->mpf_checksum = smp_compute_checksum(mf, mf->mpf_length*16); + return v; +} + +void *smp_write_floating_table(unsigned long addr, unsigned int virtualwire) +{ + /* 16 byte align the table address */ + addr = (addr + 0xf) & (~0xf); + return smp_write_floating_table_physaddr(addr, addr + SMP_FLOATING_TABLE_LEN, virtualwire); +} + +void *smp_next_mpc_entry(struct mp_config_table *mc) +{ + void *v; + v = (void *)(((char *)mc) + mc->mpc_length); + + return v; +} +static void smp_add_mpc_entry(struct mp_config_table *mc, u16 length) +{ + mc->mpc_length += length; + mc->mpc_entry_count++; +} + +void *smp_next_mpe_entry(struct mp_config_table *mc) +{ + void *v; + v = (void *)(((char *)mc) + mc->mpc_length + mc->mpe_length); + + return v; +} +static void smp_add_mpe_entry(struct mp_config_table *mc, mpe_t mpe) +{ + mc->mpe_length += mpe->mpe_length; +} + +/* + * Type 0: Processor Entries: + * Entry Type, LAPIC ID, LAPIC Version, CPU Flags EN/BP, + * CPU Signature (Stepping, Model, Family), Feature Flags + */ +void smp_write_processor(struct mp_config_table *mc, + u8 apicid, u8 apicver, u8 cpuflag, + u32 cpufeature, u32 featureflag) +{ + struct mpc_config_processor *mpc; + mpc = smp_next_mpc_entry(mc); + memset(mpc, '\0', sizeof(*mpc)); + mpc->mpc_type = MP_PROCESSOR; + mpc->mpc_apicid = apicid; + mpc->mpc_apicver = apicver; + mpc->mpc_cpuflag = cpuflag; + mpc->mpc_cpufeature = cpufeature; + mpc->mpc_featureflag = featureflag; + smp_add_mpc_entry(mc, sizeof(*mpc)); +} + +/* + * If we assume a symmetric processor configuration we can + * get all of the information we need to write the processor + * entry from the bootstrap processor. + * Plus I don't think linux really even cares. + * Having the proper apicid's in the table so the non-bootstrap + * processors can be woken up should be enough. + */ +void smp_write_processors(struct mp_config_table *mc) +{ + int boot_apic_id; + int order_id; + unsigned apic_version; + unsigned cpu_features; + unsigned cpu_feature_flags; + struct cpuid_result result; + struct device *cpu; + + boot_apic_id = lapicid(); + apic_version = lapic_read(LAPIC_LVR) & 0xff; + result = cpuid(1); + cpu_features = result.eax; + cpu_feature_flags = result.edx; + /* order the output of the cpus to fix a bug in kernel 2.6.11 */ + for(order_id = 0;order_id <256; order_id++) { + for(cpu = all_devices; cpu; cpu = cpu->next) { + unsigned long cpu_flag; + if ((cpu->path.type != DEVICE_PATH_APIC) || + (cpu->bus->dev->path.type != DEVICE_PATH_CPU_CLUSTER)) + continue; + + if (!cpu->enabled) + continue; + + cpu_flag = MPC_CPU_ENABLED; + + if (boot_apic_id == cpu->path.apic.apic_id) + cpu_flag = MPC_CPU_ENABLED | MPC_CPU_BOOTPROCESSOR; + + if(cpu->path.apic.apic_id == order_id) { + smp_write_processor(mc, + cpu->path.apic.apic_id, apic_version, + cpu_flag, cpu_features, cpu_feature_flags + ); + break; + } + } + } +} + +/* + * Type 1: Bus Entries: + * Entry Type, Bus ID, Bus Type + */ +static void smp_write_bus(struct mp_config_table *mc, + u8 id, const char *bustype) +{ + struct mpc_config_bus *mpc; + mpc = smp_next_mpc_entry(mc); + memset(mpc, '\0', sizeof(*mpc)); + mpc->mpc_type = MP_BUS; + mpc->mpc_busid = id; + memcpy(mpc->mpc_bustype, bustype, sizeof(mpc->mpc_bustype)); + smp_add_mpc_entry(mc, sizeof(*mpc)); +} + +/* + * Type 2: I/O APIC Entries: + * Entry Type, APIC ID, Version, + * APIC Flags:EN, Address + */ +void smp_write_ioapic(struct mp_config_table *mc, + u8 id, u8 ver, void *apicaddr) +{ + struct mpc_config_ioapic *mpc; + mpc = smp_next_mpc_entry(mc); + memset(mpc, '\0', sizeof(*mpc)); + mpc->mpc_type = MP_IOAPIC; + mpc->mpc_apicid = id; + mpc->mpc_apicver = ver; + mpc->mpc_flags = MPC_APIC_USABLE; + mpc->mpc_apicaddr = apicaddr; + smp_add_mpc_entry(mc, sizeof(*mpc)); +} + +/* + * Type 3: I/O Interrupt Table Entries: + * Entry Type, Int Type, Int Polarity, Int Level, + * Source Bus ID, Source Bus IRQ, Dest APIC ID, Dest PIN# + */ +void smp_write_intsrc(struct mp_config_table *mc, + u8 irqtype, u16 irqflag, + u8 srcbus, u8 srcbusirq, + u8 dstapic, u8 dstirq) +{ + struct mpc_config_intsrc *mpc; + mpc = smp_next_mpc_entry(mc); + memset(mpc, '\0', sizeof(*mpc)); + mpc->mpc_type = MP_INTSRC; + mpc->mpc_irqtype = irqtype; + mpc->mpc_irqflag = irqflag; + mpc->mpc_srcbus = srcbus; + mpc->mpc_srcbusirq = srcbusirq; + mpc->mpc_dstapic = dstapic; + mpc->mpc_dstirq = dstirq; + smp_add_mpc_entry(mc, sizeof(*mpc)); +#ifdef DEBUG_MPTABLE + printk(BIOS_DEBUG, "add intsrc srcbus 0x%x srcbusirq 0x%x, dstapic 0x%x, dstirq 0x%x\n", + srcbus, srcbusirq, dstapic, dstirq); + hexdump(__func__, mpc, sizeof(*mpc)); +#endif +} + +/* + * Type 3: I/O Interrupt Table Entries for PCI Devices: + * This has the same fields as 'Type 3: I/O Interrupt Table Entries' + * but the Source Bus IRQ field has a slightly different + * definition: + * Bits 1-0: PIRQ pin: INT_A# = 0, INT_B# = 1, INT_C# = 2, INT_D# = 3 + * Bits 2-6: Originating PCI Device Number (Not its parent bridge device number) + * Bit 7: Reserved + */ +void smp_write_pci_intsrc(struct mp_config_table *mc, + u8 irqtype, u8 srcbus, u8 dev, u8 pirq, + u8 dstapic, u8 dstirq) +{ + u8 srcbusirq = (dev << 2) | pirq; + printk(BIOS_SPEW, "\tPCI srcbusirq = 0x%x from dev = 0x%x and pirq = %x\n", srcbusirq, dev, pirq); + smp_write_intsrc(mc, irqtype, MP_IRQ_TRIGGER_LEVEL|MP_IRQ_POLARITY_LOW, srcbus, + srcbusirq, dstapic, dstirq); +} + +void smp_write_intsrc_pci_bridge(struct mp_config_table *mc, + u8 irqtype, u16 irqflag, struct device *dev, + unsigned char dstapic, unsigned char *dstirq) +{ + struct device *child; + + int i; + int srcbus; + int slot; + + struct bus *link; + unsigned char dstirq_x[4]; + + for (link = dev->link_list; link; link = link->next) { + + child = link->children; + srcbus = link->secondary; + + while (child) { + if (child->path.type != DEVICE_PATH_PCI) + goto next; + + slot = (child->path.pci.devfn >> 3); + /* round pins */ + for (i = 0; i < 4; i++) + dstirq_x[i] = dstirq[(i + slot) % 4]; + + if ((child->class >> 16) != PCI_BASE_CLASS_BRIDGE) { + /* pci device */ + printk(BIOS_DEBUG, "route irq: %s\n", dev_path(child)); + for (i = 0; i < 4; i++) + smp_write_intsrc(mc, irqtype, irqflag, srcbus, (slot<<2)|i, dstapic, dstirq_x[i]); + goto next; + } + + switch (child->class>>8) { + case PCI_CLASS_BRIDGE_PCI: + case PCI_CLASS_BRIDGE_PCMCIA: + case PCI_CLASS_BRIDGE_CARDBUS: + printk(BIOS_DEBUG, "route irq bridge: %s\n", dev_path(child)); + smp_write_intsrc_pci_bridge(mc, irqtype, irqflag, child, dstapic, dstirq_x); + } + +next: + child = child->sibling; + } + + } +} + +/* + * Type 4: Local Interrupt Assignment Entries: + * Entry Type, Int Type, Int Polarity, Int Level, + * Source Bus ID, Source Bus IRQ, Dest LAPIC ID, + * Dest LAPIC LINTIN# + */ +void smp_write_lintsrc(struct mp_config_table *mc, + u8 irqtype, u16 irqflag, + u8 srcbusid, u8 srcbusirq, + u8 destapic, u8 destapiclint) +{ + struct mpc_config_lintsrc *mpc; + mpc = smp_next_mpc_entry(mc); + memset(mpc, '\0', sizeof(*mpc)); + mpc->mpc_type = MP_LINTSRC; + mpc->mpc_irqtype = irqtype; + mpc->mpc_irqflag = irqflag; + mpc->mpc_srcbusid = srcbusid; + mpc->mpc_srcbusirq = srcbusirq; + mpc->mpc_destapic = destapic; + mpc->mpc_destapiclint = destapiclint; + smp_add_mpc_entry(mc, sizeof(*mpc)); +} + +/* + * Type 128: System Address Space Mapping Entries + * Entry Type, Entry Length, Bus ID, Address Type, + * Address Base Lo/Hi, Address Length Lo/Hi + */ +void smp_write_address_space(struct mp_config_table *mc, + u8 busid, u8 address_type, + u32 address_base_low, u32 address_base_high, + u32 address_length_low, u32 address_length_high) +{ + struct mp_exten_system_address_space *mpe; + mpe = smp_next_mpe_entry(mc); + memset(mpe, '\0', sizeof(*mpe)); + mpe->mpe_type = MPE_SYSTEM_ADDRESS_SPACE; + mpe->mpe_length = sizeof(*mpe); + mpe->mpe_busid = busid; + mpe->mpe_address_type = address_type; + mpe->mpe_address_base_low = address_base_low; + mpe->mpe_address_base_high = address_base_high; + mpe->mpe_address_length_low = address_length_low; + mpe->mpe_address_length_high = address_length_high; + smp_add_mpe_entry(mc, (mpe_t)mpe); +} + +/* + * Type 129: Bus Hierarchy Descriptor Entry + * Entry Type, Entry Length, Bus ID, Bus Info, + * Parent Bus ID + */ +void smp_write_bus_hierarchy(struct mp_config_table *mc, + u8 busid, u8 bus_info, u8 parent_busid) +{ + struct mp_exten_bus_hierarchy *mpe; + mpe = smp_next_mpe_entry(mc); + memset(mpe, '\0', sizeof(*mpe)); + mpe->mpe_type = MPE_BUS_HIERARCHY; + mpe->mpe_length = sizeof(*mpe); + mpe->mpe_busid = busid; + mpe->mpe_bus_info = bus_info; + mpe->mpe_parent_busid = parent_busid; + smp_add_mpe_entry(mc, (mpe_t)mpe); +} + +/* + * Type 130: Compatibility Bus Address Space Modifier Entry + * Entry Type, Entry Length, Bus ID, Address Modifier + * Predefined Range List + */ +void smp_write_compatibility_address_space(struct mp_config_table *mc, + u8 busid, u8 address_modifier, + u32 range_list) +{ + struct mp_exten_compatibility_address_space *mpe; + mpe = smp_next_mpe_entry(mc); + memset(mpe, '\0', sizeof(*mpe)); + mpe->mpe_type = MPE_COMPATIBILITY_ADDRESS_SPACE; + mpe->mpe_length = sizeof(*mpe); + mpe->mpe_busid = busid; + mpe->mpe_address_modifier = address_modifier; + mpe->mpe_range_list = range_list; + smp_add_mpe_entry(mc, (mpe_t)mpe); +} + +void mptable_lintsrc(struct mp_config_table *mc, unsigned long bus_isa) +{ + smp_write_lintsrc(mc, mp_ExtINT, MP_IRQ_TRIGGER_EDGE|MP_IRQ_POLARITY_HIGH, bus_isa, 0x0, MP_APIC_ALL, 0x0); + smp_write_lintsrc(mc, mp_NMI, MP_IRQ_TRIGGER_EDGE|MP_IRQ_POLARITY_HIGH, bus_isa, 0x0, MP_APIC_ALL, 0x1); +} + +void mptable_add_isa_interrupts(struct mp_config_table *mc, unsigned long bus_isa, unsigned long apicid, int external_int2) +{ +/*I/O Ints: Type Trigger Polarity Bus ID IRQ APIC ID PIN# */ + smp_write_intsrc(mc, external_int2?mp_INT:mp_ExtINT, + MP_IRQ_TRIGGER_EDGE|MP_IRQ_POLARITY_HIGH, bus_isa, 0x0, apicid, 0x0); + smp_write_intsrc(mc, mp_INT, MP_IRQ_TRIGGER_EDGE|MP_IRQ_POLARITY_HIGH, bus_isa, 0x1, apicid, 0x1); + smp_write_intsrc(mc, external_int2?mp_ExtINT:mp_INT, + MP_IRQ_TRIGGER_EDGE|MP_IRQ_POLARITY_HIGH, bus_isa, 0x0, apicid, 0x2); + smp_write_intsrc(mc, mp_INT, MP_IRQ_TRIGGER_EDGE|MP_IRQ_POLARITY_HIGH, bus_isa, 0x3, apicid, 0x3); + smp_write_intsrc(mc, mp_INT, MP_IRQ_TRIGGER_EDGE|MP_IRQ_POLARITY_HIGH, bus_isa, 0x4, apicid, 0x4); + smp_write_intsrc(mc, mp_INT, MP_IRQ_TRIGGER_EDGE|MP_IRQ_POLARITY_HIGH, bus_isa, 0x6, apicid, 0x6); + smp_write_intsrc(mc, mp_INT, MP_IRQ_TRIGGER_EDGE|MP_IRQ_POLARITY_HIGH, bus_isa, 0x7, apicid, 0x7); + smp_write_intsrc(mc, mp_INT, MP_IRQ_TRIGGER_EDGE|MP_IRQ_POLARITY_HIGH, bus_isa, 0x8, apicid, 0x8); + smp_write_intsrc(mc, mp_INT, MP_IRQ_TRIGGER_EDGE|MP_IRQ_POLARITY_HIGH, bus_isa, 0x9, apicid, 0x9); + smp_write_intsrc(mc, mp_INT, MP_IRQ_TRIGGER_EDGE|MP_IRQ_POLARITY_HIGH, bus_isa, 0xa, apicid, 0xa); + smp_write_intsrc(mc, mp_INT, MP_IRQ_TRIGGER_EDGE|MP_IRQ_POLARITY_HIGH, bus_isa, 0xb, apicid, 0xb); + smp_write_intsrc(mc, mp_INT, MP_IRQ_TRIGGER_EDGE|MP_IRQ_POLARITY_HIGH, bus_isa, 0xc, apicid, 0xc); + smp_write_intsrc(mc, mp_INT, MP_IRQ_TRIGGER_EDGE|MP_IRQ_POLARITY_HIGH, bus_isa, 0xd, apicid, 0xd); + smp_write_intsrc(mc, mp_INT, MP_IRQ_TRIGGER_EDGE|MP_IRQ_POLARITY_HIGH, bus_isa, 0xe, apicid, 0xe); + smp_write_intsrc(mc, mp_INT, MP_IRQ_TRIGGER_EDGE|MP_IRQ_POLARITY_HIGH, bus_isa, 0xf, apicid, 0xf); +} + +void mptable_write_buses(struct mp_config_table *mc, int *max_pci_bus, int *isa_bus) { + int dummy, i, highest; + char buses[256]; + struct device *dev; + + if (!max_pci_bus) max_pci_bus = &dummy; + if (!isa_bus) isa_bus = &dummy; + + *max_pci_bus = 0; + highest = 0; + memset(buses, 0, sizeof(buses)); + + for (dev = all_devices; dev; dev = dev->next) { + struct bus *bus; + for (bus = dev->link_list; bus; bus = bus->next) { + if (bus->secondary > 255) { + printk(BIOS_ERR, "A bus claims to have a bus ID > 255?!? Aborting"); + return; + } + buses[bus->secondary] = 1; + if (highest < bus->secondary) highest = bus->secondary; + } + } + for (i=0; i <= highest; i++) { + if (buses[i]) { + smp_write_bus(mc, i, "PCI "); + *max_pci_bus = i; + } + } + *isa_bus = *max_pci_bus + 1; + smp_write_bus(mc, *isa_bus, "ISA "); +} + +void *mptable_finalize(struct mp_config_table *mc) +{ + mc->mpe_checksum = smp_compute_checksum(smp_next_mpc_entry(mc), mc->mpe_length); + mc->mpc_checksum = smp_compute_checksum(mc, mc->mpc_length); + printk(BIOS_DEBUG, "Wrote the mp table end at: %p - %p\n", mc, smp_next_mpe_entry(mc)); + return smp_next_mpe_entry(mc); +} + +unsigned long __attribute__((weak)) write_smp_table(unsigned long addr) +{ + struct drivers_generic_ioapic_config *ioapic_config; + struct mp_config_table *mc; + int isa_bus, pin, parentpin; + struct device *dev; + struct device *parent; + struct device *oldparent; + void *tmp, *v; + int isaioapic = -1, have_fixed_entries; + + v = smp_write_floating_table(addr, 0); + mc = (void *)(((char *)v) + SMP_FLOATING_TABLE_LEN); + + mptable_init(mc, LOCAL_APIC_ADDR); + + smp_write_processors(mc); + + mptable_write_buses(mc, NULL, &isa_bus); + + for(dev = all_devices; dev; dev = dev->next) { + if (dev->path.type != DEVICE_PATH_IOAPIC) + continue; + + if (!(ioapic_config = dev->chip_info)) { + printk(BIOS_ERR, "%s has no config, ignoring\n", dev_path(dev)); + continue; + } + smp_write_ioapic(mc, dev->path.ioapic.ioapic_id, + ioapic_config->version, + ioapic_config->base); + + if (ioapic_config->have_isa_interrupts) { + if (isaioapic >= 0) + printk(BIOS_ERR, "More than one IOAPIC with ISA interrupts?\n"); + else + isaioapic = dev->path.ioapic.ioapic_id; + } + } + + if (isaioapic >= 0) { + /* Legacy Interrupts */ + printk(BIOS_DEBUG, "Writing ISA IRQs\n"); + mptable_add_isa_interrupts(mc, isa_bus, isaioapic, 0); + } + + for(dev = all_devices; dev; dev = dev->next) { + + if (dev->path.type != DEVICE_PATH_PCI || !dev->enabled) + continue; + + have_fixed_entries = 0; + for (pin = 0; pin < 4; pin++) { + if (dev->pci_irq_info[pin].ioapic_dst_id) { + printk(BIOS_DEBUG, "fixed IRQ entry for: %s: INT%c# -> IOAPIC %d PIN %d\n", dev_path(dev), + pin + 'A', + dev->pci_irq_info[pin].ioapic_dst_id, + dev->pci_irq_info[pin].ioapic_irq_pin); + smp_write_intsrc(mc, mp_INT, + dev->pci_irq_info[pin].ioapic_flags, + dev->bus->secondary, + ((dev->path.pci.devfn & 0xf8) >> 1) | pin, + dev->pci_irq_info[pin].ioapic_dst_id, + dev->pci_irq_info[pin].ioapic_irq_pin); + have_fixed_entries = 1; + } + } + + if (!have_fixed_entries) { + pin = (dev->path.pci.devfn & 7) % 4; + oldparent = parent = dev; + while((parent = parent->bus->dev)) { + parentpin = (oldparent->path.pci.devfn >> 3) + (oldparent->path.pci.devfn & 7); + parentpin += dev->path.pci.devfn & 7; + parentpin += dev->path.pci.devfn >> 3; + parentpin %= 4; + + if (parent->pci_irq_info[parentpin].ioapic_dst_id) { + printk(BIOS_DEBUG, "automatic IRQ entry for %s: INT%c# -> IOAPIC %d PIN %d\n", + dev_path(dev), pin + 'A', + parent->pci_irq_info[parentpin].ioapic_dst_id, + parent->pci_irq_info[parentpin].ioapic_irq_pin); + smp_write_intsrc(mc, mp_INT, + parent->pci_irq_info[parentpin].ioapic_flags, + dev->bus->secondary, + ((dev->path.pci.devfn & 0xf8) >> 1) | pin, + parent->pci_irq_info[parentpin].ioapic_dst_id, + parent->pci_irq_info[parentpin].ioapic_irq_pin); + + break; + } + + if (parent->path.type == DEVICE_PATH_DOMAIN) { + printk(BIOS_WARNING, "no IRQ found for %s\n", dev_path(dev)); + break; + } + oldparent = parent; + } + } + } + + mptable_lintsrc(mc, isa_bus); + tmp = mptable_finalize(mc); + printk(BIOS_INFO, "MPTABLE len: %d\n", (unsigned int)((uintptr_t)tmp - + (uintptr_t)v)); + return (unsigned long)tmp; +} diff --git a/src/arch/x86/pci_ops_conf1.c b/src/arch/x86/pci_ops_conf1.c new file mode 100644 index 0000000000..77df4b314f --- /dev/null +++ b/src/arch/x86/pci_ops_conf1.c @@ -0,0 +1,71 @@ +#include +#include +#include +#include +#include +#include +/* + * Functions for accessing PCI configuration space with type 1 accesses + */ + +#if !CONFIG_PCI_IO_CFG_EXT +#define CONFIG_CMD(bus,devfn, where) (0x80000000 | (bus << 16) | \ + (devfn << 8) | (where & ~3)) +#else +#define CONFIG_CMD(bus,devfn, where) (0x80000000 | (bus << 16) | \ + (devfn << 8) | ((where & 0xff) & ~3) |\ + ((where & 0xf00)<<16)) +#endif + +static uint8_t pci_conf1_read_config8(struct bus *pbus, int bus, int devfn, + int where) +{ + outl(CONFIG_CMD(bus, devfn, where), 0xCF8); + return inb(0xCFC + (where & 3)); +} + +static uint16_t pci_conf1_read_config16(struct bus *pbus, int bus, int devfn, + int where) +{ + outl(CONFIG_CMD(bus, devfn, where), 0xCF8); + return inw(0xCFC + (where & 2)); +} + +static uint32_t pci_conf1_read_config32(struct bus *pbus, int bus, int devfn, + int where) +{ + outl(CONFIG_CMD(bus, devfn, where), 0xCF8); + return inl(0xCFC); +} + +static void pci_conf1_write_config8(struct bus *pbus, int bus, int devfn, + int where, uint8_t value) +{ + outl(CONFIG_CMD(bus, devfn, where), 0xCF8); + outb(value, 0xCFC + (where & 3)); +} + +static void pci_conf1_write_config16(struct bus *pbus, int bus, int devfn, + int where, uint16_t value) +{ + outl(CONFIG_CMD(bus, devfn, where), 0xCF8); + outw(value, 0xCFC + (where & 2)); +} + +static void pci_conf1_write_config32(struct bus *pbus, int bus, int devfn, + int where, uint32_t value) +{ + outl(CONFIG_CMD(bus, devfn, where), 0xCF8); + outl(value, 0xCFC); +} + +#undef CONFIG_CMD + +const struct pci_bus_operations pci_cf8_conf1 = { + .read8 = pci_conf1_read_config8, + .read16 = pci_conf1_read_config16, + .read32 = pci_conf1_read_config32, + .write8 = pci_conf1_write_config8, + .write16 = pci_conf1_write_config16, + .write32 = pci_conf1_write_config32, +}; diff --git a/src/arch/x86/pci_ops_mmconf.c b/src/arch/x86/pci_ops_mmconf.c new file mode 100644 index 0000000000..e4fa128551 --- /dev/null +++ b/src/arch/x86/pci_ops_mmconf.c @@ -0,0 +1,61 @@ +#include +#include +#include +#include +#include +#include + +/* + * Functions for accessing PCI configuration space with mmconf accesses + */ + +#define PCI_MMIO_ADDR(SEGBUS, DEVFN, WHERE, MASK) \ + ((void *)(((uintptr_t)CONFIG_MMCONF_BASE_ADDRESS |\ + (((SEGBUS) & 0xFFF) << 20) |\ + (((DEVFN) & 0xFF) << 12) |\ + ((WHERE) & 0xFFF)) & ~MASK)) + +static uint8_t pci_mmconf_read_config8(struct bus *pbus, int bus, int devfn, + int where) +{ + return read8(PCI_MMIO_ADDR(bus, devfn, where, 0)); +} + +static uint16_t pci_mmconf_read_config16(struct bus *pbus, int bus, int devfn, + int where) +{ + return read16(PCI_MMIO_ADDR(bus, devfn, where, 1)); +} + +static uint32_t pci_mmconf_read_config32(struct bus *pbus, int bus, int devfn, + int where) +{ + return read32(PCI_MMIO_ADDR(bus, devfn, where, 3)); +} + +static void pci_mmconf_write_config8(struct bus *pbus, int bus, int devfn, + int where, uint8_t value) +{ + write8(PCI_MMIO_ADDR(bus, devfn, where, 0), value); +} + +static void pci_mmconf_write_config16(struct bus *pbus, int bus, int devfn, + int where, uint16_t value) +{ + write16(PCI_MMIO_ADDR(bus, devfn, where, 1), value); +} + +static void pci_mmconf_write_config32(struct bus *pbus, int bus, int devfn, + int where, uint32_t value) +{ + write32(PCI_MMIO_ADDR(bus, devfn, where, 3), value); +} + +const struct pci_bus_operations pci_ops_mmconf = { + .read8 = pci_mmconf_read_config8, + .read16 = pci_mmconf_read_config16, + .read32 = pci_mmconf_read_config32, + .write8 = pci_mmconf_write_config8, + .write16 = pci_mmconf_write_config16, + .write32 = pci_mmconf_write_config32, +}; diff --git a/src/arch/x86/pirq_routing.c b/src/arch/x86/pirq_routing.c new file mode 100644 index 0000000000..7fe20b25ab --- /dev/null +++ b/src/arch/x86/pirq_routing.c @@ -0,0 +1,208 @@ +/* + * This file is part of the coreboot project. + * + * Copyright (C) 2012 Alexandru Gagniuc + * Copyright (C) 2010 Stefan Reinauer + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +#include +#include +#include +#include + +#if CONFIG_DEBUG_PIRQ +static void check_pirq_routing_table(struct irq_routing_table *rt) +{ + uint8_t *addr = (uint8_t *)rt; + uint8_t sum=0; + int i; + + printk(BIOS_INFO, "Checking Interrupt Routing Table consistency...\n"); + + if (sizeof(struct irq_routing_table) != rt->size) { + printk(BIOS_WARNING, "Inconsistent Interrupt Routing Table size (0x%x/0x%x).\n", + (unsigned int) sizeof(struct irq_routing_table), + rt->size + ); + rt->size=sizeof(struct irq_routing_table); + } + + for (i = 0; i < rt->size; i++) + sum += addr[i]; + + printk(BIOS_DEBUG, "%s(): Interrupt Routing Table located at %p.\n", + __func__, addr); + + + sum = rt->checksum - sum; + + if (sum != rt->checksum) { + printk(BIOS_WARNING, "Interrupt Routing Table checksum is: 0x%02x but should be: 0x%02x.\n", + rt->checksum, sum); + rt->checksum = sum; + } + + if (rt->signature != PIRQ_SIGNATURE || rt->version != PIRQ_VERSION || + rt->size % 16 ) { + printk(BIOS_WARNING, "Interrupt Routing Table not valid.\n"); + return; + } + + sum = 0; + for (i=0; isize; i++) + sum += addr[i]; + + /* We're manually fixing the checksum above. This warning can probably + * never happen because if the target location is read-only this + * function would have bailed out earlier. + */ + if (sum) { + printk(BIOS_WARNING, "Checksum error in Interrupt Routing Table " + "could not be fixed.\n"); + } + + printk(BIOS_INFO, "done.\n"); +} + +static int verify_copy_pirq_routing_table(unsigned long addr, const struct irq_routing_table *routing_table) +{ + int i; + uint8_t *rt_orig, *rt_curr; + + rt_curr = (uint8_t*)addr; + rt_orig = (uint8_t*)routing_table; + printk(BIOS_INFO, "Verifying copy of Interrupt Routing Table at 0x%08lx... ", addr); + for (i = 0; i < routing_table->size; i++) { + if (*(rt_curr + i) != *(rt_orig + i)) { + printk(BIOS_INFO, "failed\n"); + return -1; + } + } + printk(BIOS_INFO, "done\n"); + + check_pirq_routing_table((struct irq_routing_table *)addr); + + return 0; +} +#endif + +#if CONFIG_PIRQ_ROUTE +static u8 pirq_get_next_free_irq(u8* pirq, u16 bitmap) +{ + int i, link; + u8 irq = 0; + for (i = 2; i <= 15; i++) + { + /* Can we assign this IRQ ? */ + if (!((bitmap >> i) & 1)) + continue; + /* We can, Now let's assume we can use this IRQ */ + irq = i; + /* And assume we have not yet routed it */ + int already_routed = 0; + /* Have we already routed it ? */ + for(link = 0; link < CONFIG_MAX_PIRQ_LINKS; link++) { + if (pirq[link] == irq) { + already_routed = 1; + break; + } + } + /* If it's not yet routed, use it */ + if(!already_routed) + break; + /* But if it was already routed, try the next one */ + continue; + } + /* Now we got our IRQ */ + return irq; +} + +static void pirq_route_irqs(unsigned long addr) +{ + int i, intx, num_entries; + unsigned char irq_slot[MAX_INTX_ENTRIES]; + unsigned char pirq[CONFIG_MAX_PIRQ_LINKS]; + struct irq_routing_table *pirq_tbl; + + memset(pirq, 0, CONFIG_MAX_PIRQ_LINKS); + + pirq_tbl = (struct irq_routing_table *)(addr); + num_entries = (pirq_tbl->size - 32) / 16; + + /* Set PCI IRQs. */ + for (i = 0; i < num_entries; i++) { + + printk(BIOS_DEBUG, "PIRQ Entry %d Dev/Fn: %X Slot: %d\n", i, + pirq_tbl->slots[i].devfn >> 3, pirq_tbl->slots[i].slot); + + for (intx = 0; intx < MAX_INTX_ENTRIES; intx++) { + + int link = pirq_tbl->slots[i].irq[intx].link; + int bitmap = pirq_tbl->slots[i].irq[intx].bitmap; + int irq = 0; + + printk(BIOS_DEBUG, "INT: %c link: %x bitmap: %x ", + 'A' + intx, link, bitmap); + + if (!bitmap|| !link || link > CONFIG_MAX_PIRQ_LINKS) { + + printk(BIOS_DEBUG, "not routed\n"); + irq_slot[intx] = irq; + continue; + } + + /* yet not routed */ + if (!pirq[link - 1]) + { + irq = pirq_get_next_free_irq(pirq, bitmap); + if (irq) + pirq[link - 1] = irq; + } + else + irq = pirq[link - 1]; + + printk(BIOS_DEBUG, "IRQ: %d\n", irq); + irq_slot[intx] = irq; + } + + /* Bus, device, slots IRQs for {A,B,C,D}. */ + pci_assign_irqs(pirq_tbl->slots[i].bus, + pirq_tbl->slots[i].devfn >> 3, irq_slot); + } + + for(i = 0; i < CONFIG_MAX_PIRQ_LINKS; i++) + printk(BIOS_DEBUG, "PIRQ%c: %d\n", i + 'A', pirq[i]); + + pirq_assign_irqs(pirq); +} +#endif + +unsigned long copy_pirq_routing_table(unsigned long addr, const struct irq_routing_table *routing_table) +{ + /* Align the table to be 16 byte aligned. */ + addr = ALIGN(addr, 16); + + /* This table must be between 0xf0000 & 0x100000 */ + printk(BIOS_INFO, "Copying Interrupt Routing Table to 0x%08lx... ", addr); + memcpy((void *)addr, routing_table, routing_table->size); + printk(BIOS_INFO, "done.\n"); +#if CONFIG_DEBUG_PIRQ + verify_copy_pirq_routing_table(addr, routing_table); +#endif +#if CONFIG_PIRQ_ROUTE + pirq_route_irqs(addr); +#endif + return addr + routing_table->size; +} diff --git a/src/arch/x86/prologue.inc b/src/arch/x86/prologue.inc new file mode 100644 index 0000000000..e0100b5127 --- /dev/null +++ b/src/arch/x86/prologue.inc @@ -0,0 +1,23 @@ +/* + * This file is part of the coreboot project. + * + * Copyright (C) 2002 Eric Biederman + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; version 2 of the License. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc. + */ + +#include + +.section ".rom.data", "a", @progbits +.section ".rom.text", "ax", @progbits diff --git a/src/arch/x86/romcc_console.c b/src/arch/x86/romcc_console.c new file mode 100644 index 0000000000..bfc35bc74c --- /dev/null +++ b/src/arch/x86/romcc_console.c @@ -0,0 +1,87 @@ +/* + * This file is part of the coreboot project. + * + * Copyright (C) 2003 Eric Biederman + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; version 2 of the License. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc. + */ + +#include +#include +#include +#include + +/* Include the sources. */ +#if CONFIG_CONSOLE_SERIAL && CONFIG_DRIVERS_UART_8250IO +#include "drivers/uart/util.c" +#include "drivers/uart/uart8250io.c" +#endif +#if CONFIG_CONSOLE_NE2K +#include "drivers/net/ne2k.c" +#endif + +void console_hw_init(void) +{ +#if CONFIG_CONSOLE_SERIAL + uart_init(CONFIG_UART_FOR_CONSOLE); +#endif +#if CONFIG_CONSOLE_NE2K + ne2k_init(CONFIG_CONSOLE_NE2K_IO_PORT); +#endif +} + +void console_tx_byte(unsigned char byte) +{ +#if CONFIG_CONSOLE_SERIAL + uart_tx_byte(CONFIG_UART_FOR_CONSOLE, byte); +#endif +#if CONFIG_CONSOLE_NE2K + ne2k_append_data_byte(byte, CONFIG_CONSOLE_NE2K_IO_PORT); +#endif +} + +void console_tx_flush(void) +{ +#if CONFIG_CONSOLE_SERIAL + uart_tx_flush(CONFIG_UART_FOR_CONSOLE); +#endif +#if CONFIG_CONSOLE_NE2K + ne2k_transmit(CONFIG_CONSOLE_NE2K_IO_PORT); +#endif +} + +#include +#include +#include + +void console_init(void) +{ + static const char console_test[] = + "\n\ncoreboot-" + COREBOOT_VERSION + COREBOOT_EXTRA_VERSION + " " + COREBOOT_BUILD + " romstage starting...\n"; + + console_hw_init(); + + print_info(console_test); +} + +void die(const char *msg) +{ + print_emerg(msg); + halt(); +} diff --git a/src/arch/x86/romstage.ld b/src/arch/x86/romstage.ld new file mode 100644 index 0000000000..951ca656a3 --- /dev/null +++ b/src/arch/x86/romstage.ld @@ -0,0 +1,87 @@ +/* + * This file is part of the coreboot project. + * + * Copyright (C) 2006 Advanced Micro Devices, Inc. + * Copyright (C) 2008-2010 coresystems GmbH + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; version 2 of the License. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc. + */ + +TARGET(binary) +SECTIONS +{ + . = ROMSTAGE_BASE; + + .rom . : { + _rom = .; + *(.rom.text); + *(.rom.text.*); + *(.text); + *(.text.*); + *(.rom.data); + . = ALIGN(4); + _cbmem_init_hooks = .; + KEEP(*(.rodata.cbmem_init_hooks)); + _ecbmem_init_hooks = .; + *(.rodata); + *(.rodata.*); + *(.rom.data.*); + . = ALIGN(16); + _erom = .; + } + + /DISCARD/ : { + *(.comment) + *(.note) + *(.comment.*) + *(.note.*) + *(.eh_frame); + } + + . = CONFIG_DCACHE_RAM_BASE; + .car.data . (NOLOAD) : { + _car_data_start = .; +#if IS_ENABLED(CONFIG_HAS_PRECBMEM_TIMESTAMP_REGION) + _timestamp = .; + . = . + 0x100; + _etimestamp = .; +#endif + *(.car.global_data); + _car_data_end = .; + /* The preram cbmem console area comes last to take advantage + * of a zero-sized array to hold the memconsole contents. + * However, collisions within the cache-as-ram region cannot be + * statically checked because the cache-as-ram region usage is + * cpu/chipset dependent. */ + _preram_cbmem_console = .; + _epreram_cbmem_console = . + (CONFIG_LATE_CBMEM_INIT ? 0 : 0xc00); + } + + /* Global variables are not allowed in romstage + * This section is checked during stage creation to ensure + * that there are no global variables present + */ + + . = 0xffffff00; + .illegal_globals . : { + *(EXCLUDE_FILE ("*/libagesa.*.a:" "*/buildOpts.romstage.o" "*/agesawrapper.romstage.o" "*/vendorcode/amd/agesa/*" "*/vendorcode/amd/cimx/*") .data) + *(EXCLUDE_FILE ("*/libagesa.*.a:" "*/buildOpts.romstage.o" "*/agesawrapper.romstage.o" "*/vendorcode/amd/agesa/*" "*/vendorcode/amd/cimx/*") .data.*) + *(.bss) + *(.bss.*) + *(.sbss) + *(.sbss.*) + } + + _bogus = ASSERT((CONFIG_DCACHE_RAM_SIZE == 0) || (SIZEOF(.car.data) + 0xc00 <= CONFIG_DCACHE_RAM_SIZE), "Cache as RAM area is too full"); +} diff --git a/src/arch/x86/smbios.c b/src/arch/x86/smbios.c new file mode 100644 index 0000000000..a1f05daeaf --- /dev/null +++ b/src/arch/x86/smbios.c @@ -0,0 +1,581 @@ +/* + * This file is part of the coreboot project. + * + * Copyright (C) 2015 Timothy Pearson , Raptor Engineering + * Copyright (C) 2011 Sven Schnelle + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; version 2 of + * the License. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#if CONFIG_CHROMEOS +#include +#endif + +static u8 smbios_checksum(u8 *p, u32 length) +{ + u8 ret = 0; + while (length--) + ret += *p++; + return -ret; +} + + +int smbios_add_string(char *start, const char *str) +{ + int i = 1; + char *p = start; + + for(;;) { + if (!*p) { + strcpy(p, str); + p += strlen(str); + *p++ = '\0'; + *p++ = '\0'; + return i; + } + + if (!strcmp(p, str)) + return i; + + p += strlen(p)+1; + i++; + } +} + +int smbios_string_table_len(char *start) +{ + char *p = start; + int i, len = 0; + + while(*p) { + i = strlen(p) + 1; + p += i; + len += i; + } + return len + 1; +} + +static int smbios_cpu_vendor(char *start) +{ + char tmp[13] = "Unknown"; + u32 *_tmp = (u32 *)tmp; + struct cpuid_result res; + + if (cpu_have_cpuid()) { + res = cpuid(0); + _tmp[0] = res.ebx; + _tmp[1] = res.edx; + _tmp[2] = res.ecx; + tmp[12] = '\0'; + } + + return smbios_add_string(start, tmp); +} + +static int smbios_processor_name(char *start) +{ + char tmp[49] = "Unknown Processor Name"; + u32 *_tmp = (u32 *)tmp; + struct cpuid_result res; + int i; + + if (cpu_have_cpuid()) { + res = cpuid(0x80000000); + if (res.eax >= 0x80000004) { + for (i = 0; i < 3; i++) { + res = cpuid(0x80000002 + i); + _tmp[i * 4 + 0] = res.eax; + _tmp[i * 4 + 1] = res.ebx; + _tmp[i * 4 + 2] = res.ecx; + _tmp[i * 4 + 3] = res.edx; + } + tmp[48] = 0; + } + } + return smbios_add_string(start, tmp); +} + +/* this function will fill the corresponding manufacturer */ +void smbios_fill_dimm_manufacturer_from_id(uint16_t mod_id, struct smbios_type17 *t) +{ + switch (mod_id) { + case 0x987f: + t->manufacturer = smbios_add_string(t->eos, + "Hynix"); + break; + case 0xad80: + t->manufacturer = smbios_add_string(t->eos, + "Hynix/Hyundai"); + break; + case 0xce80: + t->manufacturer = smbios_add_string(t->eos, + "Samsung"); + break; + case 0xfe02: + t->manufacturer = smbios_add_string(t->eos, + "Elpida"); + break; + case 0xff2c: + t->manufacturer = smbios_add_string(t->eos, + "Micron"); + break; + default: { + char string_buffer[256]; + snprintf(string_buffer, sizeof(string_buffer), + "Unknown (%x)", mod_id); + t->manufacturer = smbios_add_string(t->eos, + string_buffer); + break; + } + } +} + +static int create_smbios_type17_for_dimm(struct dimm_info *dimm, + unsigned long *current, int *handle) +{ + struct smbios_type17 *t = (struct smbios_type17 *)*current; + uint8_t length; + char locator[40]; + + memset(t, 0, sizeof(struct smbios_type17)); + t->memory_type = dimm->ddr_type; + t->clock_speed = dimm->ddr_frequency; + t->speed = dimm->ddr_frequency; + t->type = SMBIOS_MEMORY_DEVICE; + t->size = dimm->dimm_size; + t->data_width = 8 * (1 << (dimm->bus_width & 0x7)); + t->total_width = t->data_width + 8 * ((dimm->bus_width & 0x18) >> 3); + + switch (dimm->mod_type) { + case SPD_RDIMM: + case SPD_MINI_RDIMM: + t->form_factor = MEMORY_FORMFACTOR_RIMM; + break; + case SPD_UDIMM: + case SPD_MICRO_DIMM: + case SPD_MINI_UDIMM: + t->form_factor = MEMORY_FORMFACTOR_DIMM; + break; + case SPD_SODIMM: + t->form_factor = MEMORY_FORMFACTOR_SODIMM; + break; + default: + t->form_factor = MEMORY_FORMFACTOR_UNKNOWN; + break; + } + + smbios_fill_dimm_manufacturer_from_id(dimm->mod_id, t); + /* put '\0' in the end of data */ + length = sizeof(dimm->serial); + dimm->serial[length - 1] = '\0'; + if (dimm->serial[0] == 0) + t->serial_number = smbios_add_string(t->eos, "None"); + else + t->serial_number = smbios_add_string(t->eos, + (const char *)dimm->serial); + + snprintf(locator, sizeof(locator), "Channel-%d-DIMM-%d", + dimm->channel_num, dimm->dimm_num); + t->device_locator = smbios_add_string(t->eos, locator); + + snprintf(locator, sizeof(locator), "BANK %d", dimm->bank_locator); + t->bank_locator = smbios_add_string(t->eos, locator); + + /* put '\0' in the end of data */ + length = sizeof(dimm->module_part_number); + dimm->module_part_number[length - 1] = '\0'; + t->part_number = smbios_add_string(t->eos, + (const char *)dimm->module_part_number); + + /* Synchronous = 1 */ + t->type_detail = 0x0080; + /* no handle for error information */ + t->memory_error_information_handle = 0xFFFE; + t->attributes = dimm->rank_per_dimm; + t->handle = *handle; + *handle += 1; + t->length = sizeof(struct smbios_type17) - 2; + return t->length + smbios_string_table_len(t->eos); +} + +const char *__attribute__((weak)) smbios_mainboard_bios_version(void) +{ + if (strlen(CONFIG_LOCALVERSION)) + return CONFIG_LOCALVERSION; + else + return coreboot_version; +} + +static int smbios_write_type0(unsigned long *current, int handle) +{ + struct smbios_type0 *t = (struct smbios_type0 *)*current; + int len = sizeof(struct smbios_type0); + + memset(t, 0, sizeof(struct smbios_type0)); + t->type = SMBIOS_BIOS_INFORMATION; + t->handle = handle; + t->length = len - 2; + + t->vendor = smbios_add_string(t->eos, "coreboot"); +#if !CONFIG_CHROMEOS + t->bios_release_date = smbios_add_string(t->eos, coreboot_dmi_date); + + t->bios_version = smbios_add_string(t->eos, smbios_mainboard_bios_version()); +#else +#define SPACES \ + " " + t->bios_release_date = smbios_add_string(t->eos, coreboot_dmi_date); +#if IS_ENABLED(CONFIG_HAVE_ACPI_TABLES) + u32 version_offset = (u32)smbios_string_table_len(t->eos); +#endif + t->bios_version = smbios_add_string(t->eos, SPACES); + +#if IS_ENABLED(CONFIG_HAVE_ACPI_TABLES) + /* SMBIOS offsets start at 1 rather than 0 */ + vboot_data->vbt10 = (u32)t->eos + (version_offset - 1); +#endif +#endif /* CONFIG_CHROMEOS */ + + t->bios_rom_size = (CONFIG_ROM_SIZE / 65535) - 1; + + t->system_bios_major_release = 4; + t->bios_characteristics = + BIOS_CHARACTERISTICS_PCI_SUPPORTED | +#if CONFIG_CARDBUS_PLUGIN_SUPPORT + BIOS_CHARACTERISTICS_PC_CARD | +#endif + BIOS_CHARACTERISTICS_SELECTABLE_BOOT | + BIOS_CHARACTERISTICS_UPGRADEABLE; + +#if CONFIG_HAVE_ACPI_TABLES + t->bios_characteristics_ext1 = BIOS_EXT1_CHARACTERISTICS_ACPI; +#endif + t->bios_characteristics_ext2 = BIOS_EXT2_CHARACTERISTICS_TARGET; + len = t->length + smbios_string_table_len(t->eos); + *current += len; + return len; +} + +#if !CONFIG_SMBIOS_PROVIDED_BY_MOBO + +const char *__attribute__((weak)) smbios_mainboard_serial_number(void) +{ + return CONFIG_MAINBOARD_SERIAL_NUMBER; +} + +const char *__attribute__((weak)) smbios_mainboard_version(void) +{ + return CONFIG_MAINBOARD_VERSION; +} + +const char *__attribute__((weak)) smbios_mainboard_manufacturer(void) +{ + return CONFIG_MAINBOARD_SMBIOS_MANUFACTURER; +} + +const char *__attribute__((weak)) smbios_mainboard_product_name(void) +{ + return CONFIG_MAINBOARD_SMBIOS_PRODUCT_NAME; +} + +void __attribute__((weak)) smbios_mainboard_set_uuid(u8 *uuid) +{ + /* leave all zero */ +} +#endif + +#ifdef CONFIG_MAINBOARD_FAMILY +const char *smbios_mainboard_family(void) +{ + return CONFIG_MAINBOARD_FAMILY; +} +#endif /* CONFIG_MAINBOARD_FAMILY */ + +static int smbios_write_type1(unsigned long *current, int handle) +{ + struct smbios_type1 *t = (struct smbios_type1 *)*current; + int len = sizeof(struct smbios_type1); + + memset(t, 0, sizeof(struct smbios_type1)); + t->type = SMBIOS_SYSTEM_INFORMATION; + t->handle = handle; + t->length = len - 2; + t->manufacturer = smbios_add_string(t->eos, smbios_mainboard_manufacturer()); + t->product_name = smbios_add_string(t->eos, smbios_mainboard_product_name()); + t->serial_number = smbios_add_string(t->eos, smbios_mainboard_serial_number()); + t->version = smbios_add_string(t->eos, smbios_mainboard_version()); +#ifdef CONFIG_MAINBOARD_FAMILY + t->family = smbios_add_string(t->eos, smbios_mainboard_family()); +#endif + smbios_mainboard_set_uuid(t->uuid); + len = t->length + smbios_string_table_len(t->eos); + *current += len; + return len; +} + +static int smbios_write_type2(unsigned long *current, int handle) +{ + struct smbios_type2 *t = (struct smbios_type2 *)*current; + int len = sizeof(struct smbios_type2); + + memset(t, 0, sizeof(struct smbios_type2)); + t->type = SMBIOS_BOARD_INFORMATION; + t->handle = handle; + t->length = len - 2; + t->manufacturer = smbios_add_string(t->eos, smbios_mainboard_manufacturer()); + t->product_name = smbios_add_string(t->eos, smbios_mainboard_product_name()); + t->serial_number = smbios_add_string(t->eos, smbios_mainboard_serial_number()); + t->version = smbios_add_string(t->eos, smbios_mainboard_version()); + len = t->length + smbios_string_table_len(t->eos); + *current += len; + return len; +} + +static int smbios_write_type3(unsigned long *current, int handle) +{ + struct smbios_type3 *t = (struct smbios_type3 *)*current; + int len = sizeof(struct smbios_type3); + + memset(t, 0, sizeof(struct smbios_type3)); + t->type = SMBIOS_SYSTEM_ENCLOSURE; + t->handle = handle; + t->length = len - 2; + t->manufacturer = smbios_add_string(t->eos, smbios_mainboard_manufacturer()); + t->bootup_state = SMBIOS_STATE_SAFE; + t->power_supply_state = SMBIOS_STATE_SAFE; + t->thermal_state = SMBIOS_STATE_SAFE; + if(IS_ENABLED(CONFIG_SYSTEM_TYPE_LAPTOP)) { + t->_type = SMBIOS_ENCLOSURE_NOTEBOOK; + } else { + t->_type = SMBIOS_ENCLOSURE_DESKTOP; + } + t->security_status = SMBIOS_STATE_SAFE; + len = t->length + smbios_string_table_len(t->eos); + *current += len; + return len; +} + +static int smbios_write_type4(unsigned long *current, int handle) +{ + struct cpuid_result res; + struct smbios_type4 *t = (struct smbios_type4 *)*current; + int len = sizeof(struct smbios_type4); + + /* Provide sane defaults even for CPU without CPUID */ + res.eax = res.edx = 0; + res.ebx = 0x10000; + + if (cpu_have_cpuid()) { + res = cpuid(1); + } + + memset(t, 0, sizeof(struct smbios_type4)); + t->type = SMBIOS_PROCESSOR_INFORMATION; + t->handle = handle; + t->length = len - 2; + t->processor_id[0] = res.eax; + t->processor_id[1] = res.edx; + t->processor_manufacturer = smbios_cpu_vendor(t->eos); + t->processor_version = smbios_processor_name(t->eos); + t->processor_family = (res.eax > 0) ? 0x0c : 0x6; + t->processor_type = 3; /* System Processor */ + t->processor_upgrade = 0x06; + t->core_count = (res.ebx >> 16) & 0xff; + t->l1_cache_handle = 0xffff; + t->l2_cache_handle = 0xffff; + t->l3_cache_handle = 0xffff; + t->processor_upgrade = 1; + len = t->length + smbios_string_table_len(t->eos); + *current += len; + return len; +} + +static int smbios_write_type11(unsigned long *current, int *handle) +{ + struct smbios_type11 *t = (struct smbios_type11 *)*current; + int len; + struct device *dev; + + memset(t, 0, sizeof *t); + t->type = SMBIOS_OEM_STRINGS; + t->handle = *handle; + t->length = len = sizeof *t - 2; + + for(dev = all_devices; dev; dev = dev->next) { + if (dev->ops && dev->ops->get_smbios_strings) + dev->ops->get_smbios_strings(dev, t); + } + + if (t->count == 0) { + memset(t, 0, sizeof *t); + return 0; + } + + len += smbios_string_table_len(t->eos); + + *current += len; + (*handle)++; + return len; +} + +static int smbios_write_type17(unsigned long *current, int *handle) +{ + int len = sizeof(struct smbios_type17); + int i; + + struct memory_info *meminfo; + meminfo = cbmem_find(CBMEM_ID_MEMINFO); + if (meminfo == NULL) + return 0; /* can't find mem info in cbmem */ + + printk(BIOS_INFO, "Create SMBIOS type 17\n"); + for (i = 0; i < meminfo->dimm_cnt && i < ARRAY_SIZE(meminfo->dimm); i++) { + struct dimm_info *dimm; + dimm = &meminfo->dimm[i]; + len = create_smbios_type17_for_dimm(dimm, current, handle); + *current += len; + } + return meminfo->dimm_cnt * len; +} + +static int smbios_write_type32(unsigned long *current, int handle) +{ + struct smbios_type32 *t = (struct smbios_type32 *)*current; + int len = sizeof(struct smbios_type32); + + memset(t, 0, sizeof(struct smbios_type32)); + t->type = SMBIOS_SYSTEM_BOOT_INFORMATION; + t->handle = handle; + t->length = len - 2; + *current += len; + return len; +} + +int smbios_write_type41(unsigned long *current, int *handle, + const char *name, u8 instance, u16 segment, + u8 bus, u8 device, u8 function) +{ + struct smbios_type41 *t = (struct smbios_type41 *)*current; + int len = sizeof(struct smbios_type41); + + memset(t, 0, sizeof(struct smbios_type41)); + t->type = SMBIOS_ONBOARD_DEVICES_EXTENDED_INFORMATION; + t->handle = *handle; + t->length = len - 2; + t->reference_designation = smbios_add_string(t->eos, name); + t->device_type = SMBIOS_DEVICE_TYPE_OTHER; + t->device_status = 1; + t->device_type_instance = instance; + t->segment_group_number = segment; + t->bus_number = bus; + t->device_number = device; + t->function_number = function; + + len = t->length + smbios_string_table_len(t->eos); + *current += len; + *handle += 1; + return len; +} + +static int smbios_write_type127(unsigned long *current, int handle) +{ + struct smbios_type127 *t = (struct smbios_type127 *)*current; + int len = sizeof(struct smbios_type127); + + memset(t, 0, sizeof(struct smbios_type127)); + t->type = SMBIOS_END_OF_TABLE; + t->handle = handle; + t->length = len - 2; + *current += len; + return len; +} + +static int smbios_walk_device_tree(struct device *tree, int *handle, unsigned long *current) +{ + struct device *dev; + int len = 0; + + for(dev = tree; dev; dev = dev->next) { + printk(BIOS_INFO, "%s (%s)\n", dev_path(dev), dev_name(dev)); + + if (dev->ops && dev->ops->get_smbios_data) + len += dev->ops->get_smbios_data(dev, handle, current); + } + return len; +} + +#define update_max(len, max_len, stmt) do { int tmp = stmt; max_len = MAX(max_len, tmp); len += tmp; } while(0) +unsigned long smbios_write_tables(unsigned long current) +{ + struct smbios_entry *se; + unsigned long tables; + int len = 0; + int max_struct_size = 0; + int handle = 0; + + current = ALIGN(current, 16); + printk(BIOS_DEBUG, "%s: %08lx\n", __func__, current); + + se = (struct smbios_entry *)current; + current += sizeof(struct smbios_entry); + current = ALIGN(current, 16); + + tables = current; + update_max(len, max_struct_size, smbios_write_type0(¤t, handle++)); + update_max(len, max_struct_size, smbios_write_type1(¤t, handle++)); + update_max(len, max_struct_size, smbios_write_type2(¤t, handle++)); + update_max(len, max_struct_size, smbios_write_type3(¤t, handle++)); + update_max(len, max_struct_size, smbios_write_type4(¤t, handle++)); + update_max(len, max_struct_size, smbios_write_type11(¤t, &handle)); +#if CONFIG_ELOG + update_max(len, max_struct_size, elog_smbios_write_type15(¤t, handle++)); +#endif + update_max(len, max_struct_size, smbios_write_type17(¤t, &handle)); + update_max(len, max_struct_size, smbios_write_type32(¤t, handle++)); + + update_max(len, max_struct_size, smbios_walk_device_tree(all_devices, &handle, ¤t)); + + update_max(len, max_struct_size, smbios_write_type127(¤t, handle++)); + + memset(se, 0, sizeof(struct smbios_entry)); + memcpy(se->anchor, "_SM_", 4); + se->length = sizeof(struct smbios_entry); + se->major_version = 2; + se->minor_version = 7; + se->max_struct_size = max_struct_size; + se->struct_count = handle; + memcpy(se->intermediate_anchor_string, "_DMI_", 5); + + se->struct_table_address = (u32)tables; + se->struct_table_length = len; + + se->intermediate_checksum = smbios_checksum((u8 *)se + 0x10, + sizeof(struct smbios_entry) - 0x10); + se->checksum = smbios_checksum((u8 *)se, sizeof(struct smbios_entry)); + return current; +} diff --git a/src/arch/x86/stages.c b/src/arch/x86/stages.c new file mode 100644 index 0000000000..c06abe6793 --- /dev/null +++ b/src/arch/x86/stages.c @@ -0,0 +1,25 @@ +/* + * This file is part of the coreboot project. + * + * Copyright (C) 2010 coresystems GmbH + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; version 2 of the License. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc. + */ + +static void skip_romstage(void) +{ + asm volatile ( + "jmp __main\n" + ); +} diff --git a/src/arch/x86/tables.c b/src/arch/x86/tables.c new file mode 100644 index 0000000000..3d645633f0 --- /dev/null +++ b/src/arch/x86/tables.c @@ -0,0 +1,221 @@ +/* + * This file is part of the coreboot project. + * + * Copyright (C) 2003 Eric Biederman + * Copyright (C) 2005 Steve Magnani + * Copyright (C) 2008-2009 coresystems GmbH + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; version 2 of the License. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +void write_tables(void) +{ + unsigned long low_table_start, low_table_end; + unsigned long rom_table_start, rom_table_end; + + /* Even if high tables are configured, some tables are copied both to + * the low and the high area, so payloads and OSes don't need to know + * about the high tables. + */ + unsigned long high_table_pointer; + + rom_table_start = 0xf0000; + rom_table_end = 0xf0000; + + /* Start low addr at 0x500, so we don't run into conflicts with the BDA + * in case our data structures grow beyond 0x400. Only GDT + * and the coreboot table use low_tables. + */ + low_table_start = 0; + low_table_end = 0x500; + +#if CONFIG_GENERATE_PIRQ_TABLE +#define MAX_PIRQ_TABLE_SIZE (4 * 1024) + post_code(0x9a); + + /* This table must be between 0x0f0000 and 0x100000 */ + rom_table_end = write_pirq_routing_table(rom_table_end); + rom_table_end = ALIGN(rom_table_end, 1024); + + /* And add a high table version for those payloads that + * want to live in the F segment + */ + high_table_pointer = (unsigned long)cbmem_add(CBMEM_ID_PIRQ, MAX_PIRQ_TABLE_SIZE); + if (high_table_pointer) { + unsigned long new_high_table_pointer; + new_high_table_pointer = write_pirq_routing_table(high_table_pointer); + // FIXME make pirq table code intelligent enough to know how + // much space it's going to need. + if (new_high_table_pointer > (high_table_pointer + MAX_PIRQ_TABLE_SIZE)) { + printk(BIOS_ERR, "ERROR: Increase PIRQ size.\n"); + } + printk(BIOS_DEBUG, "PIRQ table: %ld bytes.\n", + new_high_table_pointer - high_table_pointer); + } + +#endif + +#if CONFIG_GENERATE_MP_TABLE +#define MAX_MP_TABLE_SIZE (4 * 1024) + post_code(0x9b); + + /* The smp table must be in 0-1K, 639K-640K, or 960K-1M */ + rom_table_end = write_smp_table(rom_table_end); + rom_table_end = ALIGN(rom_table_end, 1024); + + high_table_pointer = (unsigned long)cbmem_add(CBMEM_ID_MPTABLE, MAX_MP_TABLE_SIZE); + if (high_table_pointer) { + unsigned long new_high_table_pointer; + new_high_table_pointer = write_smp_table(high_table_pointer); + // FIXME make mp table code intelligent enough to know how + // much space it's going to need. + if (new_high_table_pointer > (high_table_pointer + MAX_MP_TABLE_SIZE)) { + printk(BIOS_ERR, "ERROR: Increase MP table size.\n"); + } + + printk(BIOS_DEBUG, "MP table: %ld bytes.\n", + new_high_table_pointer - high_table_pointer); + } +#endif /* CONFIG_GENERATE_MP_TABLE */ + +#if CONFIG_HAVE_ACPI_TABLES +#define MAX_ACPI_SIZE (144 * 1024) + + post_code(0x9c); + + /* Write ACPI tables to F segment and high tables area */ + + /* Ok, this is a bit hacky still, because some day we want to have this + * completely dynamic. But right now we are setting fixed sizes. + * It's probably still better than the old high_table_base code because + * now at least we know when we have an overflow in the area. + * + * We want to use 1MB - 64K for Resume backup. We use 512B for TOC and + * 512 byte for GDT, 4K for PIRQ and 4K for MP table and 8KB for the + * coreboot table. This leaves us with 47KB for all of ACPI. Let's see + * how far we get. + */ + high_table_pointer = (unsigned long)cbmem_add(CBMEM_ID_ACPI, MAX_ACPI_SIZE); + if (high_table_pointer) { + unsigned long acpi_start = high_table_pointer; + unsigned long new_high_table_pointer; + + rom_table_end = ALIGN(rom_table_end, 16); + new_high_table_pointer = write_acpi_tables(high_table_pointer); + if (new_high_table_pointer > ( high_table_pointer + MAX_ACPI_SIZE)) { + printk(BIOS_ERR, "ERROR: Increase ACPI size\n"); + } + printk(BIOS_DEBUG, "ACPI tables: %ld bytes.\n", + new_high_table_pointer - high_table_pointer); + + /* Now we need to create a low table copy of the RSDP. */ + + /* First we look for the high table RSDP */ + while (acpi_start < new_high_table_pointer) { + if (memcmp(((acpi_rsdp_t *)acpi_start)->signature, RSDP_SIG, 8) == 0) { + break; + } + acpi_start++; + } + + /* Now, if we found the RSDP, we take the RSDT and XSDT pointer + * from it in order to write the low RSDP + */ + if (acpi_start < new_high_table_pointer) { + acpi_rsdp_t *low_rsdp = (acpi_rsdp_t *)rom_table_end, + *high_rsdp = (acpi_rsdp_t *)acpi_start; + + /* Technically rsdp length varies but coreboot always + writes longest size available. */ + memcpy(low_rsdp, high_rsdp, sizeof(acpi_rsdp_t)); + } else { + printk(BIOS_ERR, "ERROR: Didn't find RSDP in high table.\n"); + } + rom_table_end = ALIGN(rom_table_end + sizeof(acpi_rsdp_t), 16); + } else { + rom_table_end = write_acpi_tables(rom_table_end); + rom_table_end = ALIGN(rom_table_end, 1024); + } + +#endif +#define MAX_SMBIOS_SIZE 2048 +#if CONFIG_GENERATE_SMBIOS_TABLES + high_table_pointer = (unsigned long)cbmem_add(CBMEM_ID_SMBIOS, MAX_SMBIOS_SIZE); + if (high_table_pointer) { + unsigned long new_high_table_pointer; + + new_high_table_pointer = smbios_write_tables(high_table_pointer); + rom_table_end = ALIGN(rom_table_end, 16); + memcpy((void *)rom_table_end, (void *)high_table_pointer, sizeof(struct smbios_entry)); + rom_table_end += sizeof(struct smbios_entry); + + if (new_high_table_pointer > ( high_table_pointer + MAX_SMBIOS_SIZE)) { + printk(BIOS_ERR, "ERROR: Increase SMBIOS size\n"); + } + printk(BIOS_DEBUG, "SMBIOS tables: %ld bytes.\n", + new_high_table_pointer - high_table_pointer); + } else { + unsigned long new_rom_table_end = smbios_write_tables(rom_table_end); + printk(BIOS_DEBUG, "SMBIOS size %ld bytes\n", new_rom_table_end - rom_table_end); + rom_table_end = ALIGN(new_rom_table_end, 16); + } +#endif + + post_code(0x9e); + +#define MAX_COREBOOT_TABLE_SIZE (32 * 1024) + post_code(0x9d); + + high_table_pointer = (unsigned long)cbmem_add(CBMEM_ID_CBTABLE, MAX_COREBOOT_TABLE_SIZE); + + if (high_table_pointer) { + unsigned long new_high_table_pointer; + + /* FIXME: The high_table_base parameter is not reference when tables are high, + * or high_table_pointer >1 MB. + */ + u64 fixme_high_tables_base = 0; + + /* Also put a forwarder entry into 0-4K */ + new_high_table_pointer = write_coreboot_table(low_table_start, low_table_end, + fixme_high_tables_base, high_table_pointer); + + if (new_high_table_pointer > (high_table_pointer + + MAX_COREBOOT_TABLE_SIZE)) + printk(BIOS_ERR, "%s: coreboot table didn't fit (%lx)\n", + __func__, new_high_table_pointer - + high_table_pointer); + + printk(BIOS_DEBUG, "coreboot table: %ld bytes.\n", + new_high_table_pointer - high_table_pointer); + } else { + /* The coreboot table must be in 0-4K or 960K-1M */ + write_coreboot_table(low_table_start, low_table_end, + rom_table_start, rom_table_end); + } + + /* Print CBMEM sections */ + cbmem_list(); +} diff --git a/src/arch/x86/thread.c b/src/arch/x86/thread.c new file mode 100644 index 0000000000..f81a2d20ca --- /dev/null +++ b/src/arch/x86/thread.c @@ -0,0 +1,65 @@ +/* + * This file is part of the coreboot project. + * + * Copyright (C) 2013 Google, Inc. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; version 2 of the License. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc. + */ + +#include + +/* The stack frame looks like the following after a pushad instruction. */ +struct pushad_regs { + uint32_t edi; /* Offset 0x00 */ + uint32_t esi; /* Offset 0x04 */ + uint32_t ebp; /* Offset 0x08 */ + uint32_t esp; /* Offset 0x0c */ + uint32_t ebx; /* Offset 0x10 */ + uint32_t edx; /* Offset 0x14 */ + uint32_t ecx; /* Offset 0x18 */ + uint32_t eax; /* Offset 0x1c */ +}; + +static inline uintptr_t push_stack(uintptr_t cur_stack, uintptr_t value) +{ + uintptr_t *addr; + + cur_stack -= sizeof(value); + addr = (uintptr_t *)cur_stack; + *addr = value; + return cur_stack; +} + +void arch_prepare_thread(struct thread *t, + void asmlinkage (*thread_entry)(void *), void *arg) +{ + uintptr_t stack = t->stack_current; + + /* Imitate thread_entry(t) with return address of 0. thread_entry() + * is assumed to never return. */ + stack = push_stack(stack, (uintptr_t)arg); + stack = push_stack(stack, (uintptr_t)0); + stack = push_stack(stack, (uintptr_t)thread_entry); + /* Make room for the registers. Ignore intial values. */ + stack -= sizeof(struct pushad_regs); + + t->stack_current = stack; +} + +void *arch_get_thread_stackbase(void) +{ + /* defined in c_start.S */ + extern u8 thread_stacks[]; + return &thread_stacks[0]; +} diff --git a/src/arch/x86/thread_switch.S b/src/arch/x86/thread_switch.S new file mode 100644 index 0000000000..52d4d3094b --- /dev/null +++ b/src/arch/x86/thread_switch.S @@ -0,0 +1,58 @@ +/* + * This file is part of the coreboot project. + * + * Copyright (C) 2013 Google, Inc. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; version 2 of the License. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc. + */ +.code32 +.text + +/* + * stack layout after pushad: + * +------------+ + * | save stack | <-- esp + 0x28 + * +------------+ + * | new stack | <-- esp + 0x24 + * +------------+ + * | ret addr | <-- esp + 0x20 + * +------------+ + * | eax | <-- esp + 0x1c + * +------------+ + * | ecx | <-- esp + 0x18 + * +------------+ + * | edx | <-- esp + 0x14 + * +------------+ + * | ebx | <-- esp + 0x10 + * +------------+ + * | orig esp | <-- esp + 0x0c + * +------------+ + * | ebp | <-- esp + 0x08 + * +------------+ + * | esi | <-- esp + 0x04 + * +------------+ + * | edi | <-- esp + 0x00 + * +------------+ + */ +.globl switch_to_thread +switch_to_thread: + pusha + /* Save the current stack */ + movl 0x28(%esp), %ebx + movl %esp, (%ebx) + /* Switch to the new stack. */ + movl 0x24(%esp), %eax + movl %eax, %esp + popa + ret diff --git a/src/arch/x86/timestamp.c b/src/arch/x86/timestamp.c new file mode 100644 index 0000000000..9df505a570 --- /dev/null +++ b/src/arch/x86/timestamp.c @@ -0,0 +1,26 @@ +/* + * This file is part of the coreboot project. + * + * Copyright 2013 Google Inc. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; version 2 of the License. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc. + */ + +#include +#include + +uint64_t timestamp_get(void) +{ + return rdtscll(); +} diff --git a/src/arch/x86/wakeup.S b/src/arch/x86/wakeup.S new file mode 100644 index 0000000000..38d6ea43ae --- /dev/null +++ b/src/arch/x86/wakeup.S @@ -0,0 +1,99 @@ +/* + * This file is part of the coreboot project. + * + * Copyright (C) 2009 Rudolf Marek + * Copyright (C) 2009 coresystems GmbH + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; version 2 of the License. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc. + */ + +#define WAKEUP_BASE 0x600 +#define RELOCATED(x) (x - __wakeup + WAKEUP_BASE) + +/* CR0 bits */ +#define PE (1 << 0) + +#ifdef __x86_64__ + .code64 +#else + .code32 +#endif + + .globl __wakeup +__wakeup: + /* First prepare the jmp to the resume vector */ + mov 0x4(%esp), %eax /* vector */ + /* last 4 bits of linear addr are taken as offset */ + andw $0x0f, %ax + movw %ax, (__wakeup_offset) + mov 0x4(%esp), %eax + /* the rest is taken as segment */ + shr $4, %eax + movw %ax, (__wakeup_segment) + + /* Then overwrite coreboot with our backed up memory */ + cld + movl 8(%esp), %esi + movl 12(%esp), %edi + movl 16(%esp), %ecx + shrl $2, %ecx + rep movsl + + /* Activate the right segment descriptor real mode. */ + ljmp $0x28, $RELOCATED(1f) +1: +.code16 + /* 16 bit code from here on... */ + + /* Load the segment registers w/ properly configured + * segment descriptors. They will retain these + * configurations (limits, writability, etc.) once + * protected mode is turned off. + */ + mov $0x30, %ax + mov %ax, %ds + mov %ax, %es + mov %ax, %fs + mov %ax, %gs + mov %ax, %ss + + /* Turn off protection */ + movl %cr0, %eax + andl $~PE, %eax + movl %eax, %cr0 + + /* Now really going into real mode */ + ljmp $0, $RELOCATED(1f) +1: + movw $0x0, %ax + movw %ax, %ds + movw %ax, %es + movw %ax, %ss + movw %ax, %fs + movw %ax, %gs + + /* This is a FAR JMP to the OS waking vector. The C code changed + * the address to be correct. + */ + .byte 0xea + +__wakeup_offset = RELOCATED(.) + .word 0x0000 + +__wakeup_segment = RELOCATED(.) + .word 0x0000 + + .globl __wakeup_size +__wakeup_size: + .long . - __wakeup diff --git a/src/arch/x86/walkcbfs.S b/src/arch/x86/walkcbfs.S new file mode 100644 index 0000000000..60eb8b53b0 --- /dev/null +++ b/src/arch/x86/walkcbfs.S @@ -0,0 +1,117 @@ +#define CBFS_HEADER_PTR 0xfffffffc + +#define CBFS_HEADER_MAGIC 0 +#define CBFS_HEADER_VERSION (CBFS_HEADER_MAGIC + 4) +#define CBFS_HEADER_ROMSIZE (CBFS_HEADER_VERSION + 4) +#define CBFS_HEADER_BOOTBLOCKSIZE (CBFS_HEADER_ROMSIZE + 4) +#define CBFS_HEADER_ALIGN (CBFS_HEADER_BOOTBLOCKSIZE + 4) +#define CBFS_HEADER_OFFSET (CBFS_HEADER_ALIGN + 4) + +#define CBFS_FILE_MAGIC 0 +#define CBFS_FILE_LEN (CBFS_FILE_MAGIC + 8) +#define CBFS_FILE_TYPE (CBFS_FILE_LEN + 4) +#define CBFS_FILE_CHECKSUM (CBFS_FILE_TYPE + 4) +#define CBFS_FILE_OFFSET (CBFS_FILE_CHECKSUM + 4) + +#define CBFS_FILE_STRUCTSIZE (CBFS_FILE_OFFSET + 4) + +/* + * input %esi: filename + * input %esp: return address (not pointer to return address!) + * output %eax: pointer to CBFS header + * clobbers %ebx, %ecx, %edi + */ +walkcbfs_asm: + cld + + mov CBFS_HEADER_PTR, %eax + mov CBFS_HEADER_ROMSIZE(%eax), %ecx + bswap %ecx + mov $0, %ebx + sub %ecx, %ebx /* rom base address in ebx */ + mov CBFS_HEADER_OFFSET(%eax), %ecx + bswap %ecx + add %ecx, %ebx /* address where we start looking for LARCHIVEs */ + + /* determine filename length */ + mov $0, %eax +1: + cmpb $0, (%eax,%esi) + jz 2f + add $1, %eax + jmp 1b +2: + add $1, %eax +walker: + mov 0(%ebx), %edi /* Check for LARCHIVE header */ + cmp %edi, filemagic + jne searchfile + mov 4(%ebx), %edi + cmp %edi, filemagic+4 + jne searchfile + + /* LARCHIVE header found */ + mov %ebx, %edi + add $CBFS_FILE_STRUCTSIZE, %edi /* edi = address of first byte after struct cbfs_file */ + mov %eax, %ecx + repe cmpsb + /* zero flag set if strings are equal */ + jnz tryharder + + /* we found it! */ + mov %ebx, %eax + jmp *%esp + +tryharder: + sub %ebx, %edi + sub $CBFS_FILE_STRUCTSIZE, %edi /* edi = # of walked bytes */ + sub %edi, %esi /* esi = start of filename */ + + /* ebx = ecx = (current+offset+len+ALIGN-1) & ~(ALIGN-1) */ + mov CBFS_FILE_OFFSET(%ebx), %ecx + bswap %ecx + add %ebx, %ecx + mov CBFS_FILE_LEN(%ebx), %edi + bswap %edi + add %edi, %ecx + mov CBFS_HEADER_PTR, %edi + mov CBFS_HEADER_ALIGN(%edi), %edi + bswap %edi + sub $1, %edi + add %edi, %ecx + not %edi + and %edi, %ecx + + /* if oldaddr >= addr, leave */ + cmp %ebx, %ecx + jbe out + + mov %ecx, %ebx + +check_for_exit: + /* look if we should exit: did we pass into the bootblock already? */ + mov CBFS_HEADER_PTR, %ecx + mov CBFS_HEADER_BOOTBLOCKSIZE(%ecx), %ecx + bswap %ecx + not %ecx + add $1, %ecx + + cmp %ecx, %ebx + /* if bootblockstart >= addr (==we're still in the data area) , jump back */ + jbe walker + +out: + mov $0, %eax + jmp *%esp + + +searchfile: + /* if filemagic isn't found, move forward cbfs_header->align bytes */ + mov CBFS_HEADER_PTR, %edi + mov CBFS_HEADER_ALIGN(%edi), %edi + bswap %edi + add %edi, %ebx + jmp check_for_exit + +filemagic: + .ascii "LARCHIVE" diff --git a/src/mainboard/bifferos/bifferboard/romstage.c b/src/mainboard/bifferos/bifferboard/romstage.c index b0f0477986..dc616edab5 100644 --- a/src/mainboard/bifferos/bifferboard/romstage.c +++ b/src/mainboard/bifferos/bifferboard/romstage.c @@ -23,7 +23,7 @@ #include #include #include -#include "arch/x86/lib/romcc_console.c" +#include "arch/x86/romcc_console.c" #include #include diff --git a/src/mainboard/dmp/vortex86ex/romstage.c b/src/mainboard/dmp/vortex86ex/romstage.c index 3dcea68fb5..36925db255 100644 --- a/src/mainboard/dmp/vortex86ex/romstage.c +++ b/src/mainboard/dmp/vortex86ex/romstage.c @@ -21,7 +21,7 @@ #include #include #include -#include "arch/x86/lib/romcc_console.c" +#include "arch/x86/romcc_console.c" #include #include #include diff --git a/src/northbridge/intel/fsp_rangeley/Makefile.inc b/src/northbridge/intel/fsp_rangeley/Makefile.inc index eaa1a77e88..3b88913452 100644 --- a/src/northbridge/intel/fsp_rangeley/Makefile.inc +++ b/src/northbridge/intel/fsp_rangeley/Makefile.inc @@ -28,7 +28,7 @@ ramstage-y += acpi.c ramstage-y += port_access.c romstage-y += raminit.c -romstage-y += ../../../arch/x86/lib/walkcbfs.S +romstage-y += ../../../arch/x86/walkcbfs.S romstage-y += port_access.c smm-$(CONFIG_HAVE_SMI_HANDLER) += udelay.c diff --git a/src/northbridge/intel/fsp_sandybridge/Makefile.inc b/src/northbridge/intel/fsp_sandybridge/Makefile.inc index 42c16fa6ca..6c5e09f9b4 100644 --- a/src/northbridge/intel/fsp_sandybridge/Makefile.inc +++ b/src/northbridge/intel/fsp_sandybridge/Makefile.inc @@ -31,7 +31,7 @@ romstage-y += raminit.c romstage-y += ram_calc.c romstage-y += early_init.c romstage-y += report_platform.c -romstage-y += ../../../arch/x86/lib/walkcbfs.S +romstage-y += ../../../arch/x86/walkcbfs.S smm-$(CONFIG_HAVE_SMI_HANDLER) += udelay.c smm-$(CONFIG_HAVE_SMI_HANDLER) += finalize.c diff --git a/src/northbridge/intel/haswell/Makefile.inc b/src/northbridge/intel/haswell/Makefile.inc index 330dc00b91..ad4b2ba2f3 100644 --- a/src/northbridge/intel/haswell/Makefile.inc +++ b/src/northbridge/intel/haswell/Makefile.inc @@ -32,7 +32,7 @@ romstage-y += raminit.c romstage-y += mrccache.c romstage-y += early_init.c romstage-y += report_platform.c -romstage-y += ../../../arch/x86/lib/walkcbfs.S +romstage-y += ../../../arch/x86/walkcbfs.S smm-$(CONFIG_HAVE_SMI_HANDLER) += finalize.c diff --git a/src/northbridge/intel/nehalem/Makefile.inc b/src/northbridge/intel/nehalem/Makefile.inc index cb02fd8a68..e5b4385ea9 100644 --- a/src/northbridge/intel/nehalem/Makefile.inc +++ b/src/northbridge/intel/nehalem/Makefile.inc @@ -31,7 +31,7 @@ romstage-y += ram_calc.c romstage-y += raminit.c romstage-y += early_init.c romstage-y += ../sandybridge/mrccache.c -romstage-y += ../../../arch/x86/lib/walkcbfs.S +romstage-y += ../../../arch/x86/walkcbfs.S smm-$(CONFIG_HAVE_SMI_HANDLER) += finalize.c diff --git a/src/northbridge/intel/sandybridge/Makefile.inc b/src/northbridge/intel/sandybridge/Makefile.inc index cf79459df2..407b61d8a7 100644 --- a/src/northbridge/intel/sandybridge/Makefile.inc +++ b/src/northbridge/intel/sandybridge/Makefile.inc @@ -40,7 +40,7 @@ romstage-$(CONFIG_NORTHBRIDGE_INTEL_SANDYBRIDGE_NATIVE) += ../../../device/dram/ romstage-y += mrccache.c romstage-y += early_init.c romstage-y += report_platform.c -romstage-y += ../../../arch/x86/lib/walkcbfs.S +romstage-y += ../../../arch/x86/walkcbfs.S smm-$(CONFIG_HAVE_SMI_HANDLER) += udelay.c smm-$(CONFIG_HAVE_SMI_HANDLER) += finalize.c -- cgit v1.2.1