soc/apollolake: SOC specific SMM code
Add SMI handlers that map to SOC specific SMI events Update relocation_handler in mp_ops Change-Id: Idefddaf41cf28240f5f8172b00462a7f893889e7 Signed-off-by: Hannah Williams <hannah.williams@intel.com> Reviewed-on: https://review.coreboot.org/14808 Tested-by: build bot (Jenkins) Reviewed-by: Aaron Durbin <adurbin@chromium.org>
This commit is contained in:
parent
ba0fc470dd
commit
d9c84ca7ef
|
@ -22,6 +22,7 @@ config CPU_SPECIFIC_OPTIONS
|
||||||
select COLLECT_TIMESTAMPS
|
select COLLECT_TIMESTAMPS
|
||||||
select COMMON_FADT
|
select COMMON_FADT
|
||||||
select HAVE_INTEL_FIRMWARE
|
select HAVE_INTEL_FIRMWARE
|
||||||
|
select HAVE_SMI_HANDLER
|
||||||
select MMCONF_SUPPORT
|
select MMCONF_SUPPORT
|
||||||
select MMCONF_SUPPORT_DEFAULT
|
select MMCONF_SUPPORT_DEFAULT
|
||||||
select NO_FIXED_XIP_ROM_SIZE
|
select NO_FIXED_XIP_ROM_SIZE
|
||||||
|
@ -35,7 +36,9 @@ config CPU_SPECIFIC_OPTIONS
|
||||||
select POSTCAR_STAGE
|
select POSTCAR_STAGE
|
||||||
select REG_SCRIPT
|
select REG_SCRIPT
|
||||||
select RELOCATABLE_RAMSTAGE # Build fails if this is not selected
|
select RELOCATABLE_RAMSTAGE # Build fails if this is not selected
|
||||||
|
select SMM_TSEG
|
||||||
select SOC_INTEL_COMMON
|
select SOC_INTEL_COMMON
|
||||||
|
select SOC_INTEL_COMMON_SMI
|
||||||
select SPI_FLASH
|
select SPI_FLASH
|
||||||
select UDELAY_TSC
|
select UDELAY_TSC
|
||||||
select TSC_CONSTANT_RATE
|
select TSC_CONSTANT_RATE
|
||||||
|
|
|
@ -15,11 +15,9 @@ bootblock-y += car.c
|
||||||
bootblock-y += gpio.c
|
bootblock-y += gpio.c
|
||||||
bootblock-y += lpc_lib.c
|
bootblock-y += lpc_lib.c
|
||||||
bootblock-y += mmap_boot.c
|
bootblock-y += mmap_boot.c
|
||||||
bootblock-y += placeholders.c
|
|
||||||
bootblock-y += tsc_freq.c
|
bootblock-y += tsc_freq.c
|
||||||
bootblock-$(CONFIG_SOC_UART_DEBUG) += uart_early.c
|
bootblock-$(CONFIG_SOC_UART_DEBUG) += uart_early.c
|
||||||
|
|
||||||
romstage-y += placeholders.c
|
|
||||||
romstage-y += car.c
|
romstage-y += car.c
|
||||||
romstage-$(CONFIG_PLATFORM_USES_FSP2_0) += romstage.c
|
romstage-$(CONFIG_PLATFORM_USES_FSP2_0) += romstage.c
|
||||||
romstage-y += gpio.c
|
romstage-y += gpio.c
|
||||||
|
@ -31,13 +29,12 @@ romstage-y += mmap_boot.c
|
||||||
romstage-y += tsc_freq.c
|
romstage-y += tsc_freq.c
|
||||||
romstage-y += pmutil.c
|
romstage-y += pmutil.c
|
||||||
|
|
||||||
smm-y += placeholders.c
|
|
||||||
smm-y += pmutil.c
|
smm-y += pmutil.c
|
||||||
|
smm-y += smihandler.c
|
||||||
|
|
||||||
ramstage-$(CONFIG_HAVE_ACPI_TABLES) += acpi.c
|
ramstage-$(CONFIG_HAVE_ACPI_TABLES) += acpi.c
|
||||||
ramstage-y += cpu.c
|
ramstage-y += cpu.c
|
||||||
ramstage-y += chip.c
|
ramstage-y += chip.c
|
||||||
ramstage-y += placeholders.c
|
|
||||||
ramstage-y += gpio.c
|
ramstage-y += gpio.c
|
||||||
ramstage-y += graphics.c
|
ramstage-y += graphics.c
|
||||||
ramstage-$(CONFIG_SOC_UART_DEBUG) += uart_early.c
|
ramstage-$(CONFIG_SOC_UART_DEBUG) += uart_early.c
|
||||||
|
@ -51,6 +48,7 @@ ramstage-y += spi.c
|
||||||
ramstage-y += tsc_freq.c
|
ramstage-y += tsc_freq.c
|
||||||
ramstage-y += pmutil.c
|
ramstage-y += pmutil.c
|
||||||
ramstage-y += pmc.c
|
ramstage-y += pmc.c
|
||||||
|
ramstage-y += smi.c
|
||||||
|
|
||||||
postcar-y += exit_car.S
|
postcar-y += exit_car.S
|
||||||
postcar-y += memmap.c
|
postcar-y += memmap.c
|
||||||
|
|
|
@ -25,6 +25,7 @@
|
||||||
#include <device/device.h>
|
#include <device/device.h>
|
||||||
#include <device/pci.h>
|
#include <device/pci.h>
|
||||||
#include <soc/cpu.h>
|
#include <soc/cpu.h>
|
||||||
|
#include <soc/smm.h>
|
||||||
|
|
||||||
static struct device_operations cpu_dev_ops = {
|
static struct device_operations cpu_dev_ops = {
|
||||||
.init = DEVICE_NOOP,
|
.init = DEVICE_NOOP,
|
||||||
|
@ -41,6 +42,18 @@ static const struct cpu_driver driver __cpu_driver = {
|
||||||
.id_table = cpu_table,
|
.id_table = cpu_table,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
* MP and SMM loading initialization.
|
||||||
|
*/
|
||||||
|
struct smm_relocation_attrs {
|
||||||
|
uint32_t smbase;
|
||||||
|
uint32_t smrr_base;
|
||||||
|
uint32_t smrr_mask;
|
||||||
|
};
|
||||||
|
|
||||||
|
static struct smm_relocation_attrs relo_attrs;
|
||||||
|
|
||||||
static void read_cpu_topology(unsigned int *num_phys, unsigned int *num_virt)
|
static void read_cpu_topology(unsigned int *num_phys, unsigned int *num_virt)
|
||||||
{
|
{
|
||||||
msr_t msr;
|
msr_t msr;
|
||||||
|
@ -75,6 +88,42 @@ static int get_cpu_count(void)
|
||||||
return num_virt_cores;
|
return num_virt_cores;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void get_smm_info(uintptr_t *perm_smbase, size_t *perm_smsize,
|
||||||
|
size_t *smm_save_state_size)
|
||||||
|
{
|
||||||
|
void *smm_base;
|
||||||
|
size_t smm_size;
|
||||||
|
|
||||||
|
/* All range registers are aligned to 4KiB */
|
||||||
|
const uint32_t rmask = ~((1 << 12) - 1);
|
||||||
|
|
||||||
|
/* Initialize global tracking state. */
|
||||||
|
smm_region(&smm_base, &smm_size);
|
||||||
|
relo_attrs.smbase = (uint32_t)smm_base;
|
||||||
|
relo_attrs.smrr_base = relo_attrs.smbase | MTRR_TYPE_WRBACK;
|
||||||
|
relo_attrs.smrr_mask = ~(smm_size - 1) & rmask;
|
||||||
|
relo_attrs.smrr_mask |= MTRR_PHYS_MASK_VALID;
|
||||||
|
|
||||||
|
*perm_smbase = relo_attrs.smbase;
|
||||||
|
*perm_smsize = smm_size - CONFIG_SMM_RESERVED_SIZE;
|
||||||
|
*smm_save_state_size = sizeof(em64t100_smm_state_save_area_t);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void relocation_handler(int cpu, uintptr_t curr_smbase,
|
||||||
|
uintptr_t staggered_smbase)
|
||||||
|
{
|
||||||
|
msr_t smrr;
|
||||||
|
em64t100_smm_state_save_area_t *smm_state;
|
||||||
|
/* Set up SMRR. */
|
||||||
|
smrr.lo = relo_attrs.smrr_base;
|
||||||
|
smrr.hi = 0;
|
||||||
|
wrmsr(SMRR_PHYS_BASE, smrr);
|
||||||
|
smrr.lo = relo_attrs.smrr_mask;
|
||||||
|
smrr.hi = 0;
|
||||||
|
wrmsr(SMRR_PHYS_MASK, smrr);
|
||||||
|
smm_state = (void *)(SMM_EM64T100_SAVE_STATE_OFFSET + curr_smbase);
|
||||||
|
smm_state->smbase = staggered_smbase;
|
||||||
|
}
|
||||||
/*
|
/*
|
||||||
* CPU initialization recipe
|
* CPU initialization recipe
|
||||||
*
|
*
|
||||||
|
@ -85,6 +134,10 @@ static int get_cpu_count(void)
|
||||||
static const struct mp_ops mp_ops = {
|
static const struct mp_ops mp_ops = {
|
||||||
.pre_mp_init = pre_mp_init,
|
.pre_mp_init = pre_mp_init,
|
||||||
.get_cpu_count = get_cpu_count,
|
.get_cpu_count = get_cpu_count,
|
||||||
|
.get_smm_info = get_smm_info,
|
||||||
|
.pre_mp_smm_init = southbridge_smm_clear_state,
|
||||||
|
.relocation_handler = relocation_handler,
|
||||||
|
.post_mp_init = southbridge_smm_enable_smi,
|
||||||
};
|
};
|
||||||
|
|
||||||
void apollolake_init_cpus(device_t dev)
|
void apollolake_init_cpus(device_t dev)
|
||||||
|
|
|
@ -0,0 +1,38 @@
|
||||||
|
/*
|
||||||
|
* This file is part of the coreboot project.
|
||||||
|
*
|
||||||
|
* Copyright (C) 2016 Intel Corp.
|
||||||
|
* (Written by Lance Zhao <lijian.zhao@intel.com> for Intel Corp.)
|
||||||
|
*
|
||||||
|
* 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.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef _SOC_SMM_H_
|
||||||
|
#define _SOC_SMM_H_
|
||||||
|
|
||||||
|
#include <stdint.h>
|
||||||
|
|
||||||
|
/* These helpers are for performing SMM relocation. */
|
||||||
|
void southbridge_clear_smi_status(void);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* The initialization of the southbridge is split into 2 compoments. One is
|
||||||
|
* for clearing the state in the SMM registers. The other is for enabling
|
||||||
|
* SMIs.
|
||||||
|
*/
|
||||||
|
void southbridge_smm_clear_state(void);
|
||||||
|
void southbridge_smm_enable_smi(void);
|
||||||
|
|
||||||
|
|
||||||
|
/* Fills in the arguments for the entire SMM region covered by chipset
|
||||||
|
* protections. e.g. TSEG. */
|
||||||
|
void smm_region(void **start, size_t *size);
|
||||||
|
#endif
|
|
@ -20,13 +20,27 @@
|
||||||
#include <device/pci.h>
|
#include <device/pci.h>
|
||||||
#include <soc/northbridge.h>
|
#include <soc/northbridge.h>
|
||||||
#include <soc/pci_devs.h>
|
#include <soc/pci_devs.h>
|
||||||
|
#include <soc/smm.h>
|
||||||
|
|
||||||
static uintptr_t smm_region_start(void)
|
static uintptr_t smm_region_start(void)
|
||||||
{
|
{
|
||||||
return ALIGN_DOWN(pci_read_config32(NB_DEV_ROOT, TSEG), 1*MiB);
|
return ALIGN_DOWN(pci_read_config32(NB_DEV_ROOT, TSEG), 1*MiB);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static size_t smm_region_size(void)
|
||||||
|
{
|
||||||
|
uintptr_t smm_end =
|
||||||
|
ALIGN_DOWN(pci_read_config32(NB_DEV_ROOT, BGSM), 1*MiB);
|
||||||
|
return smm_end - smm_region_start();
|
||||||
|
}
|
||||||
|
|
||||||
void *cbmem_top(void)
|
void *cbmem_top(void)
|
||||||
{
|
{
|
||||||
return (void *)smm_region_start();
|
return (void *)smm_region_start();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void smm_region(void **start, size_t *size)
|
||||||
|
{
|
||||||
|
*start = (void *)smm_region_start();
|
||||||
|
*size = smm_region_size();
|
||||||
|
}
|
||||||
|
|
|
@ -1,22 +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; 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.
|
|
||||||
*/
|
|
||||||
|
|
||||||
#include <cbmem.h>
|
|
||||||
#include <cpu/x86/smm.h>
|
|
||||||
#include <delay.h>
|
|
||||||
#include <rules.h>
|
|
||||||
|
|
||||||
void southbridge_smi_set_eos(void)
|
|
||||||
{
|
|
||||||
}
|
|
|
@ -0,0 +1,88 @@
|
||||||
|
/*
|
||||||
|
* This file is part of the coreboot project.
|
||||||
|
*
|
||||||
|
* Copyright (C) 2016 Intel Corp.
|
||||||
|
* (Written by Lance Zhao <lijian.zhao@intel.com> for Intel Corp.)
|
||||||
|
*
|
||||||
|
* 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.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <device/device.h>
|
||||||
|
#include <device/pci.h>
|
||||||
|
#include <console/console.h>
|
||||||
|
#include <arch/io.h>
|
||||||
|
#include <cpu/cpu.h>
|
||||||
|
#include <cpu/x86/cache.h>
|
||||||
|
#include <cpu/x86/smm.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <soc/pm.h>
|
||||||
|
#include <soc/smm.h>
|
||||||
|
|
||||||
|
void southbridge_smm_clear_state(void)
|
||||||
|
{
|
||||||
|
printk(BIOS_DEBUG, "Initializing Southbridge SMI...");
|
||||||
|
|
||||||
|
if (get_smi_en() & APMC_EN) {
|
||||||
|
printk(BIOS_INFO, "SMI# handler already enabled?\n");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
printk(BIOS_DEBUG, "Done\n");
|
||||||
|
|
||||||
|
/* Dump and clear status registers */
|
||||||
|
clear_smi_status();
|
||||||
|
clear_pm1_status();
|
||||||
|
clear_tco_status();
|
||||||
|
clear_gpe_status();
|
||||||
|
}
|
||||||
|
|
||||||
|
void southbridge_smm_enable_smi(void)
|
||||||
|
{
|
||||||
|
printk(BIOS_DEBUG, "Enabling SMIs.\n");
|
||||||
|
/* Configure events */
|
||||||
|
enable_pm1(PWRBTN_EN | GBL_EN);
|
||||||
|
disable_gpe(PME_B0_EN);
|
||||||
|
|
||||||
|
/* Enable SMI generation */
|
||||||
|
enable_smi(APMC_EN | SLP_SMI_EN | GBL_SMI_EN | EOS);
|
||||||
|
}
|
||||||
|
|
||||||
|
void southbridge_clear_smi_status(void)
|
||||||
|
{
|
||||||
|
/* Clear SMI status */
|
||||||
|
clear_smi_status();
|
||||||
|
|
||||||
|
/* Clear PM1 status */
|
||||||
|
clear_pm1_status();
|
||||||
|
|
||||||
|
/* Set EOS bit so other SMIs can occur. */
|
||||||
|
enable_smi(EOS);
|
||||||
|
}
|
||||||
|
|
||||||
|
void smm_setup_structures(void *gnvs, void *tcg, void *smi1)
|
||||||
|
{
|
||||||
|
/*
|
||||||
|
* Issue SMI to set the gnvs pointer in SMM.
|
||||||
|
* tcg and smi1 are unused.
|
||||||
|
*
|
||||||
|
* EAX = APM_CNT_GNVS_UPDATE
|
||||||
|
* EBX = gnvs pointer
|
||||||
|
* EDX = APM_CNT
|
||||||
|
*/
|
||||||
|
asm volatile (
|
||||||
|
"outb %%al, %%dx\n\t"
|
||||||
|
: /* ignore result */
|
||||||
|
: "a" (APM_CNT_GNVS_UPDATE),
|
||||||
|
"b" ((u32)gnvs),
|
||||||
|
"d" (APM_CNT)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
|
@ -0,0 +1,79 @@
|
||||||
|
/*
|
||||||
|
* This file is part of the coreboot project.
|
||||||
|
*
|
||||||
|
* Copyright (C) 2013 Google Inc.
|
||||||
|
* Copyright (C) 2015-2016 Intel Corp.
|
||||||
|
*
|
||||||
|
* 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.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <arch/hlt.h>
|
||||||
|
#include <arch/io.h>
|
||||||
|
#include <console/console.h>
|
||||||
|
#include <cpu/x86/cache.h>
|
||||||
|
#include <cpu/x86/smm.h>
|
||||||
|
#include <device/pci_def.h>
|
||||||
|
#include <elog.h>
|
||||||
|
#include <soc/nvs.h>
|
||||||
|
#include <soc/pm.h>
|
||||||
|
#include <soc/gpio.h>
|
||||||
|
#include <soc/iomap.h>
|
||||||
|
#include <soc/pci_devs.h>
|
||||||
|
#include <soc/intel/common/smi.h>
|
||||||
|
#include <spi-generic.h>
|
||||||
|
#include <stdint.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
|
||||||
|
int smm_disable_busmaster(device_t dev)
|
||||||
|
{
|
||||||
|
if (dev == PMC_DEV)
|
||||||
|
return 0;
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
const struct smm_save_state_ops *get_smm_save_state_ops(void)
|
||||||
|
{
|
||||||
|
return &em64t100_smm_ops;
|
||||||
|
}
|
||||||
|
|
||||||
|
const smi_handler_t southbridge_smi[32] = {
|
||||||
|
NULL, /* [0] reserved */
|
||||||
|
NULL, /* [1] reserved */
|
||||||
|
NULL, /* [2] BIOS_STS */
|
||||||
|
NULL, /* [3] LEGACY_USB_STS */
|
||||||
|
southbridge_smi_sleep, /* [4] SLP_SMI_STS */
|
||||||
|
southbridge_smi_apmc, /* [5] APM_STS */
|
||||||
|
NULL, /* [6] SWSMI_TMR_STS */
|
||||||
|
NULL, /* [7] reserved */
|
||||||
|
southbridge_smi_pm1, /* [8] PM1_STS */
|
||||||
|
southbridge_smi_gpe0, /* [9] GPE0_STS */
|
||||||
|
NULL, /* [10] reserved */
|
||||||
|
NULL, /* [11] reserved */
|
||||||
|
NULL, /* [12] reserved */
|
||||||
|
southbridge_smi_tco, /* [13] TCO_STS */
|
||||||
|
southbridge_smi_periodic, /* [14] PERIODIC_STS */
|
||||||
|
NULL, /* [15] SERIRQ_SMI_STS */
|
||||||
|
NULL, /* [16] SMBUS_SMI_STS */
|
||||||
|
NULL, /* [17] LEGACY_USB2_STS */
|
||||||
|
NULL, /* [18] INTEL_USB2_STS */
|
||||||
|
NULL, /* [19] reserved */
|
||||||
|
NULL, /* [20] PCI_EXP_SMI_STS */
|
||||||
|
NULL, /* [21] reserved */
|
||||||
|
NULL, /* [22] reserved */
|
||||||
|
NULL, /* [23] reserved */
|
||||||
|
NULL, /* [24] reserved */
|
||||||
|
NULL, /* [25] reserved */
|
||||||
|
NULL, /* [26] SPI_STS */
|
||||||
|
NULL, /* [27] reserved */
|
||||||
|
NULL, /* [28] PUNIT */
|
||||||
|
NULL, /* [29] GUNIT */
|
||||||
|
NULL, /* [30] reserved */
|
||||||
|
NULL /* [31] reserved */
|
||||||
|
};
|
Loading…
Reference in New Issue