diff --git a/src/cpu/intel/model_206ax/Makefile.inc b/src/cpu/intel/model_206ax/Makefile.inc index c296fd9fd5..6e0dcf61a9 100644 --- a/src/cpu/intel/model_206ax/Makefile.inc +++ b/src/cpu/intel/model_206ax/Makefile.inc @@ -1,5 +1,6 @@ ramstage-y += model_206ax_init.c subdirs-y += ../../x86/name +subdirs-y += ../smm/gen1 ramstage-y += acpi.c @@ -8,5 +9,3 @@ smm-$(CONFIG_HAVE_SMI_HANDLER) += finalize.c cpu_microcode-$(CONFIG_CPU_MICROCODE_CBFS_GENERATE) += microcode_blob.c cpu_incs += $(src)/cpu/intel/model_206ax/cache_as_ram.inc - -ramstage-$(CONFIG_HAVE_SMI_HANDLER) += smmrelocate.c diff --git a/src/cpu/intel/model_206ax/model_206ax_init.c b/src/cpu/intel/model_206ax/model_206ax_init.c index 74ad0e8372..2028af0196 100644 --- a/src/cpu/intel/model_206ax/model_206ax_init.c +++ b/src/cpu/intel/model_206ax/model_206ax_init.c @@ -35,6 +35,9 @@ #include #include "model_206ax.h" #include "chip.h" +#include + +#define CORE_THREAD_COUNT_MSR 0x35 /* * List of supported C-states in this processor @@ -473,6 +476,20 @@ static void configure_mca(void) wrmsr(IA32_MC0_STATUS + (i * 4), msr); } +int cpu_get_apic_id_map(int *apic_id_map) +{ + msr_t msr; + int num_cpus, i; + + msr = rdmsr(CORE_THREAD_COUNT_MSR); + num_cpus = msr.lo & 0xffff; + + for (i = 0; i < num_cpus && i < CONFIG_MAX_CPUS; i++) + apic_id_map[i] = i; + + return num_cpus; +} + /* * Initialize any extra cores/threads in this package. */ diff --git a/src/cpu/intel/smm/gen1/Makefile.inc b/src/cpu/intel/smm/gen1/Makefile.inc new file mode 100644 index 0000000000..09367102b1 --- /dev/null +++ b/src/cpu/intel/smm/gen1/Makefile.inc @@ -0,0 +1 @@ +ramstage-$(CONFIG_HAVE_SMI_HANDLER) += smmrelocate.c diff --git a/src/cpu/intel/smm/gen1/smi.h b/src/cpu/intel/smm/gen1/smi.h new file mode 100644 index 0000000000..475ef4b0cf --- /dev/null +++ b/src/cpu/intel/smm/gen1/smi.h @@ -0,0 +1,7 @@ +/* These helpers are for performing SMM relocation. */ +void southbridge_smm_init(void); +void southbridge_trigger_smi(void); +void southbridge_clear_smi_status(void); +void northbridge_get_tseg_base_and_size(u32 *tsegmb, u32 *tseg_size); +int cpu_get_apic_id_map(int *apic_id_map); +void northbridge_write_smram(u8 smram); diff --git a/src/cpu/intel/model_206ax/smmrelocate.c b/src/cpu/intel/smm/gen1/smmrelocate.c similarity index 67% rename from src/cpu/intel/model_206ax/smmrelocate.c rename to src/cpu/intel/smm/gen1/smmrelocate.c index 461286f7ab..bc14444dbf 100644 --- a/src/cpu/intel/model_206ax/smmrelocate.c +++ b/src/cpu/intel/smm/gen1/smmrelocate.c @@ -17,6 +17,9 @@ * Foundation, Inc. */ +/* SMM relocation with intention to work for i945-ivybridge. + Right now used for sandybridge and ivybridge. */ + #include #include #include @@ -27,19 +30,22 @@ #include #include #include -#include -#include -#include "model_206ax.h" - -#define EMRRphysBase_MSR 0x1f4 -#define EMRRphysMask_MSR 0x1f5 -#define UNCORE_EMRRphysBase_MSR 0x2f4 -#define UNCORE_EMRRphysMask_MSR 0x2f5 - -#define CORE_THREAD_COUNT_MSR 0x35 +#include "smi.h" #define SMRR_SUPPORTED (1<<11) -#define EMRR_SUPPORTED (1<<12) + +#define D_OPEN (1 << 6) +#define D_CLS (1 << 5) +#define D_LCK (1 << 4) +#define G_SMRAME (1 << 3) +#define C_BASE_SEG ((0 << 2) | (1 << 1) | (0 << 0)) + +struct ied_header { + char signature[10]; + u32 size; + u8 reserved[34]; +} __attribute__ ((packed)); + struct smm_relocation_params { u32 smram_base; @@ -48,10 +54,6 @@ struct smm_relocation_params { u32 ied_size; msr_t smrr_base; msr_t smrr_mask; - msr_t emrr_base; - msr_t emrr_mask; - msr_t uncore_emrr_base; - msr_t uncore_emrr_mask; }; /* This gets filled in and used during relocation. */ @@ -65,24 +67,6 @@ static inline void write_smrr(struct smm_relocation_params *relo_params) wrmsr(SMRRphysMask_MSR, relo_params->smrr_mask); } -static inline void write_emrr(struct smm_relocation_params *relo_params) -{ - printk(BIOS_DEBUG, "Writing EMRR. base = 0x%08x, mask=0x%08x\n", - relo_params->emrr_base.lo, relo_params->emrr_mask.lo); - wrmsr(EMRRphysBase_MSR, relo_params->emrr_base); - wrmsr(EMRRphysMask_MSR, relo_params->emrr_mask); -} - -static inline void write_uncore_emrr(struct smm_relocation_params *relo_params) -{ - printk(BIOS_DEBUG, - "Writing UNCORE_EMRR. base = 0x%08x, mask=0x%08x\n", - relo_params->uncore_emrr_base.lo, - relo_params->uncore_emrr_mask.lo); - wrmsr(UNCORE_EMRRphysBase_MSR, relo_params->uncore_emrr_base); - wrmsr(UNCORE_EMRRphysMask_MSR, relo_params->uncore_emrr_mask); -} - /* The relocation work is actually performed in SMM context, but the code * resides in the ramstage module. This occurs by trampolining from the default * SMRAM entry point to here. */ @@ -124,40 +108,18 @@ static void asmlinkage cpu_smm_do_relocation(void *arg) printk(BIOS_DEBUG, "New SMBASE=0x%08x IEDBASE=0x%08x @ %p\n", save_state->smbase, save_state->iedbase, save_state); - /* Write EMRR and SMRR MSRs based on indicated support. */ + /* Write SMRR MSRs based on indicated support. */ mtrr_cap = rdmsr(MTRRcap_MSR); if (mtrr_cap.lo & SMRR_SUPPORTED) write_smrr(relo_params); - if (mtrr_cap.lo & EMRR_SUPPORTED) { - write_emrr(relo_params); - /* UNCORE_EMRR msrs are package level. Therefore, only - * configure these MSRs on the BSP. */ - if (cpu == 0) - write_uncore_emrr(relo_params); - } - southbridge_clear_smi_status(); } -static u32 northbridge_get_base_reg(device_t dev, int reg) -{ - u32 value; - - value = pci_read_config32(dev, reg); - /* Base registers are at 1MiB granularity. */ - value &= ~((1 << 20) - 1); - return value; -} - -static void fill_in_relocation_params(device_t dev, - struct smm_relocation_params *params) +static void fill_in_relocation_params(struct smm_relocation_params *params) { u32 tseg_size; u32 tsegmb; - u32 bgsm; - u32 emrr_base; - u32 emrr_size; int phys_bits; /* All range registers are aligned to 4KiB */ const u32 rmask = ~((1 << 12) - 1); @@ -170,9 +132,7 @@ static void fill_in_relocation_params(device_t dev, * SMRAM range as well as the IED range. However, the SMRAM available * to the handler is 4MiB since the IEDRAM lives TSEGMB + 4MiB. */ - tsegmb = northbridge_get_base_reg(dev, TSEG); - bgsm = northbridge_get_base_reg(dev, BGSM); - tseg_size = bgsm - tsegmb; + northbridge_get_tseg_base_and_size(&tsegmb, &tseg_size); params->smram_base = tsegmb; params->smram_size = 4 << 20; @@ -184,27 +144,9 @@ static void fill_in_relocation_params(device_t dev, params->smrr_base.hi = 0; params->smrr_mask.lo = (~(tseg_size - 1) & rmask) | MTRRphysMaskValid; params->smrr_mask.hi = 0; - - /* The EMRR and UNCORE_EMRR are at IEDBASE + 2MiB */ - emrr_base = (params->ied_base + (2 << 20)) & rmask; - emrr_size = params->ied_size - (2 << 20); - - /* EMRR has 46 bits of valid address aligned to 4KiB. It's dependent - * on the number of physical address bits supported. */ - params->emrr_base.lo = emrr_base | MTRR_TYPE_WRBACK; - params->emrr_base.hi = 0; - params->emrr_mask.lo = (~(emrr_size - 1) & rmask) | MTRRphysMaskValid; - params->emrr_mask.hi = (1 << (phys_bits - 32)) - 1; - - /* UNCORE_EMRR has 39 bits of valid address aligned to 4KiB. */ - params->uncore_emrr_base.lo = emrr_base; - params->uncore_emrr_base.hi = 0; - params->uncore_emrr_mask.lo = (~(emrr_size - 1) & rmask) | - MTRRphysMaskValid; - params->uncore_emrr_mask.hi = (1 << (39 - 32)) - 1; } -static int install_relocation_handler(int num_cpus, +static int install_relocation_handler(int *apic_id_map, int num_cpus, struct smm_relocation_params *relo_params) { /* The default SMM entry happens serially at the default location. @@ -221,7 +163,13 @@ static int install_relocation_handler(int num_cpus, .handler_arg = (void *)relo_params, }; - return smm_setup_relocation_handler(&smm_params); + if (smm_setup_relocation_handler(&smm_params)) + return -1; + int i; + for (i = 0; i < num_cpus; i++) { + smm_params.runtime->apic_id_to_cpu[i] = apic_id_map[i]; + } + return 0; } static void setup_ied_area(struct smm_relocation_params *params) @@ -243,7 +191,7 @@ static void setup_ied_area(struct smm_relocation_params *params) memset(ied_base + (1 << 20), 0, (32 << 10)); } -static int install_permanent_handler(int num_cpus, +static int install_permanent_handler(int *apic_id_map, int num_cpus, struct smm_relocation_params *relo_params) { /* There are num_cpus concurrent stacks and num_cpus concurrent save @@ -258,38 +206,43 @@ static int install_permanent_handler(int num_cpus, printk(BIOS_DEBUG, "Installing SMM handler to 0x%08x\n", relo_params->smram_base); - return smm_load_module((void *)relo_params->smram_base, - relo_params->smram_size, &smm_params); + if (smm_load_module((void *)relo_params->smram_base, + relo_params->smram_size, &smm_params)) + return -1; + int i; + for (i = 0; i < num_cpus; i++) { + smm_params.runtime->apic_id_to_cpu[i] = apic_id_map[i]; + } + return 0; } static int cpu_smm_setup(void) { - device_t dev; int num_cpus; - msr_t msr; + int apic_id_map[CONFIG_MAX_CPUS]; printk(BIOS_DEBUG, "Setting up SMI for CPU\n"); - dev = dev_find_slot(0, PCI_DEVFN(0, 0)); + fill_in_relocation_params(&smm_reloc_params); - fill_in_relocation_params(dev, &smm_reloc_params); + /* enable the SMM memory window */ + northbridge_write_smram(D_OPEN | G_SMRAME | C_BASE_SEG); setup_ied_area(&smm_reloc_params); - msr = rdmsr(CORE_THREAD_COUNT_MSR); - num_cpus = msr.lo & 0xffff; + num_cpus = cpu_get_apic_id_map(apic_id_map); if (num_cpus > CONFIG_MAX_CPUS) { printk(BIOS_CRIT, "Error: Hardware CPUs (%d) > MAX_CPUS (%d)\n", num_cpus, CONFIG_MAX_CPUS); } - if (install_relocation_handler(num_cpus, &smm_reloc_params)) { + if (install_relocation_handler(apic_id_map, num_cpus, &smm_reloc_params)) { printk(BIOS_CRIT, "SMM Relocation handler install failed.\n"); return -1; } - if (install_permanent_handler(num_cpus, &smm_reloc_params)) { + if (install_permanent_handler(apic_id_map, num_cpus, &smm_reloc_params)) { printk(BIOS_CRIT, "SMM Permanent handler install failed.\n"); return -1; } @@ -298,6 +251,9 @@ static int cpu_smm_setup(void) /* TODO(adurbin): Is this really needed? */ wbinvd(); + /* close the SMM memory window and enable normal SMM */ + northbridge_write_smram(G_SMRAME | C_BASE_SEG); + return 0; } @@ -328,6 +284,6 @@ void smm_lock(void) * make the SMM registers writable again. */ printk(BIOS_DEBUG, "Locking SMM.\n"); - pci_write_config8(dev_find_slot(0, PCI_DEVFN(0, 0)), SMRAM, - D_LCK | G_SMRAME | C_BASE_SEG); + + northbridge_write_smram(D_LCK | G_SMRAME | C_BASE_SEG); } diff --git a/src/northbridge/intel/sandybridge/northbridge.c b/src/northbridge/intel/sandybridge/northbridge.c index 7d257f6fe3..0e0ba00cf1 100644 --- a/src/northbridge/intel/sandybridge/northbridge.c +++ b/src/northbridge/intel/sandybridge/northbridge.c @@ -36,6 +36,7 @@ #include #include "chip.h" #include "sandybridge.h" +#include static int bridge_revision_id = -1; @@ -432,6 +433,33 @@ static void northbridge_enable(device_t dev) #endif } +static u32 northbridge_get_base_reg(device_t dev, int reg) +{ + u32 value; + + value = pci_read_config32(dev, reg); + /* Base registers are at 1MiB granularity. */ + value &= ~((1 << 20) - 1); + return value; +} + +void +northbridge_get_tseg_base_and_size(u32 *tsegmb, u32 *tseg_size) +{ + device_t dev; + u32 bgsm; + dev = dev_find_slot(0, PCI_DEVFN(0, 0)); + + *tsegmb = northbridge_get_base_reg(dev, TSEG); + bgsm = northbridge_get_base_reg(dev, BGSM); + *tseg_size = bgsm - *tsegmb; +} + +void northbridge_write_smram(u8 smram) +{ + pci_write_config8(dev_find_slot(0, PCI_DEVFN(0, 0)), SMRAM, smram); +} + static struct pci_operations intel_pci_ops = { .set_subsystem = intel_set_subsystem, }; diff --git a/src/northbridge/intel/sandybridge/sandybridge.h b/src/northbridge/intel/sandybridge/sandybridge.h index 09894f71e4..6f8fcfc6bb 100644 --- a/src/northbridge/intel/sandybridge/sandybridge.h +++ b/src/northbridge/intel/sandybridge/sandybridge.h @@ -91,11 +91,6 @@ #define LAC 0x87 /* Legacy Access Control */ #define SMRAM 0x88 /* System Management RAM Control */ -#define D_OPEN (1 << 6) -#define D_CLS (1 << 5) -#define D_LCK (1 << 4) -#define G_SMRAME (1 << 3) -#define C_BASE_SEG ((0 << 2) | (1 << 1) | (0 << 0)) #define TOM 0xa0 #define TOUUD 0xa8 /* Top of Upper Usable DRAM */ @@ -200,12 +195,6 @@ #ifndef __ASSEMBLER__ static inline void barrier(void) { asm("" ::: "memory"); } -struct ied_header { - char signature[10]; - u32 size; - u8 reserved[34]; -} __attribute__ ((packed)); - #define PCI_DEVICE_ID_SB 0x0104 #define PCI_DEVICE_ID_IB 0x0154 diff --git a/src/southbridge/intel/bd82x6x/pch.h b/src/southbridge/intel/bd82x6x/pch.h index 950dbc4fd8..3ce5d63bac 100644 --- a/src/southbridge/intel/bd82x6x/pch.h +++ b/src/southbridge/intel/bd82x6x/pch.h @@ -66,11 +66,6 @@ void intel_pch_finalize_smm(void); #include "chip.h" void pch_enable(device_t dev); #endif -/* These helpers are for performing SMM relocation. */ -void southbridge_smm_init(void); -void southbridge_trigger_smi(void); -void southbridge_clear_smi_status(void); - int pch_silicon_revision(void); int pch_silicon_type(void); int pch_silicon_supported(int type, int rev); diff --git a/src/southbridge/intel/bd82x6x/smi.c b/src/southbridge/intel/bd82x6x/smi.c index 1768463065..d9c0e08c78 100644 --- a/src/southbridge/intel/bd82x6x/smi.c +++ b/src/southbridge/intel/bd82x6x/smi.c @@ -27,6 +27,7 @@ #include #include #include +#include #include "pch.h" /* While we read PMBASE dynamically in case it changed, let's