Arthur Heymans has uploaded this change for review. ( https://review.coreboot.org/c/coreboot/+/37289 )
Change subject: cpu/x86/smm: Add sinkhole mitigation to relocatable smmstub
......................................................................
cpu/x86/smm: Add sinkhole mitigation to relocatable smmstub
This adds a check for LAPIC base twice. One very early check when the
CPU is still executing in real mode checks if the LAPIC base is inside
the region [smmbase,smmbase + SMM_DEFAULT_SIZE). This cannot use
anything but a hardcoded size since even accessing the relocatable
parameters is impossible in the state of the CPU.
The actual SMI handler is located above smmbase + SMM_DEFAULT_SIZE and
before jumping to it the LAPIC base is checked against the whole SMM
region. Given that we have a working stack at this point, this is done
in C code.
UNTESTED.
Change-Id: I49927c4f4218552b732bac8aae551d845ad7f079
Signed-off-by: Arthur Heymans <arthur(a)aheymans.xyz>
---
M src/cpu/x86/smm/Makefile.inc
A src/cpu/x86/smm/sinkhole.c
M src/cpu/x86/smm/smm_stub.S
M src/include/cpu/x86/smm.h
4 files changed, 87 insertions(+), 0 deletions(-)
git pull ssh://review.coreboot.org:29418/coreboot refs/changes/89/37289/1
diff --git a/src/cpu/x86/smm/Makefile.inc b/src/cpu/x86/smm/Makefile.inc
index 11a4e67..b94f11e 100644
--- a/src/cpu/x86/smm/Makefile.inc
+++ b/src/cpu/x86/smm/Makefile.inc
@@ -45,6 +45,7 @@
postcar-y += tseg_region.c
smmstub-y += smm_stub.S
+smmstub-y += sinkhole.c
smm-y += smm_module_handler.c
diff --git a/src/cpu/x86/smm/sinkhole.c b/src/cpu/x86/smm/sinkhole.c
new file mode 100644
index 0000000..773549c
--- /dev/null
+++ b/src/cpu/x86/smm/sinkhole.c
@@ -0,0 +1,34 @@
+/*
+ * 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.
+ */
+
+#include <console/console.h>
+#include <cpu/x86/lapic_def.h>
+#include <cpu/x86/msr.h>
+#include <cpu/x86/smm.h>
+
+const extern struct smm_runtime smm_runtime;
+
+/* Don't try to recover because, if somebody tried to do shenanigans like
+ these, we have to expect more. */
+void mitigate_sinkhole(void)
+{
+ msr_t lapic_base_msr = rdmsr(LAPIC_BASE_MSR);
+ uintptr_t lapic_base = lapic_base_msr.lo & LAPIC_BASE_MSR_ADDR_MASK;
+
+ const uintptr_t smm_end = smm_runtime.smbase + smm_runtime.smm_size;
+
+ if (lapic_base > smm_runtime.smbase && lapic_base < smm_end) {
+ printk(BIOS_EMERG, "Wrong LAPIC base detected! dying...\n");
+ asm("ud2");
+ }
+}
diff --git a/src/cpu/x86/smm/smm_stub.S b/src/cpu/x86/smm/smm_stub.S
index 304ea4b..1d39ae1 100644
--- a/src/cpu/x86/smm/smm_stub.S
+++ b/src/cpu/x86/smm/smm_stub.S
@@ -22,6 +22,7 @@
*/
#include <cpu/x86/cr.h>
+#include <cpu/x86/lapic_def.h>
.code32
.section ".module_parameters", "aw", @progbits
@@ -39,6 +40,7 @@
fxsave_area_size:
.long 0
/* struct smm_runtime begins here. */
+.global smm_runtime
smm_runtime:
smbase:
.long 0
@@ -63,10 +65,51 @@
(CR0_CD | CR0_NW | CR0_PG | CR0_AM | CR0_WP | \
CR0_NE | CR0_TS | CR0_EM | CR0_MP)
+#define SMM_DEFAULT_SIZE 0x10000
+
.text
.code16
.global _start
_start:
+#if CONFIG(SMM_LAPIC_REMAP_MITIGATION)
+ /* Check if the LAPIC register block overlaps with SMM.
+ * This block needs to work without data accesses because they
+ * may be routed into the LAPIC register block.
+ * Code accesses, on the other hand, are never routed to LAPIC,
+ * which is what makes this work in the first place.
+ * This is a mitigation against the sinkhole vulnerability
+ * possible on pre sandy bridge Intel hardware.
+ */
+ mov $LAPIC_BASE_MSR, %ecx
+ rdmsr
+ and $(~0xfff), %eax
+ sub $_start, %eax
+ /* This might cover a bit more than needed but in the case that
+ this is a stub to the relocated, permanent handler it should
+ cover some parts of the permanent handler too, so no harm is
+ done. In the case that this is a stub to a relocation handler
+ coreboot did something horribly wrong if LAPIC is here.
+ This has to be 'hardcoded' as the CPU is running in real mode
+ at this point so it cannot access any relocatable variable. */
+ cmp $SMM_DEFAULT_SIZE, %eax
+ ja untampered_lapic
+1:
+ /* emit "Crash" on serial */
+ mov $(CONFIG_TTYS0_BASE), %dx
+ mov $'C', %al
+ out %al, (%dx)
+ mov $'r', %al
+ out %al, (%dx)
+ mov $'a', %al
+ out %al, (%dx)
+ mov $'s', %al
+ out %al, (%dx)
+ mov $'h', %al
+ out %al, (%dx)
+ /* now crash for real */
+ ud2
+untampered_lapic:
+#endif
movl $(smm_relocate_gdt), %ebx
lgdtl (%ebx)
@@ -174,6 +217,12 @@
/* Align stack to 16 bytes. Another 32 bytes are pushed below. */
andl $0xfffffff0, %esp
+#if CONFIG(SMM_LAPIC_REMAP_MITIGATION)
+ /* Now that we have a stack, check for against lapic base in
+ C code before jumping to the permanent handler */
+ call mitigate_sinkhole
+#endif
+
/* Call into the c-based SMM relocation function with the platform
* parameters. Equivalent to:
* struct arg = { c_handler_params, cpu_num, smm_runtime, canary };
diff --git a/src/include/cpu/x86/smm.h b/src/include/cpu/x86/smm.h
index 2e3c639..884d5cb 100644
--- a/src/include/cpu/x86/smm.h
+++ b/src/include/cpu/x86/smm.h
@@ -89,6 +89,9 @@
/* SMM Runtime helpers. */
+/* SMM Runtime sinkhole mitigation check */
+void mitigate_sinkhole(void);
+
/* Entry point for SMM modules. */
asmlinkage void smm_handler_start(void *params);
--
To view, visit https://review.coreboot.org/c/coreboot/+/37289
To unsubscribe, or for help writing mail filters, visit https://review.coreboot.org/settings
Gerrit-Project: coreboot
Gerrit-Branch: master
Gerrit-Change-Id: I49927c4f4218552b732bac8aae551d845ad7f079
Gerrit-Change-Number: 37289
Gerrit-PatchSet: 1
Gerrit-Owner: Arthur Heymans <arthur(a)aheymans.xyz>
Gerrit-Reviewer: Arthur Heymans <arthur(a)aheymans.xyz>
Gerrit-Reviewer: Martin Roth <martinroth(a)google.com>
Gerrit-Reviewer: Patrick Georgi <pgeorgi(a)google.com>
Gerrit-MessageType: newchange
Rocky Phagura has uploaded this change for review. ( https://review.coreboot.org/c/coreboot/+/43684 )
Change subject: cpu/x86/smm: SMM module loader version 2
......................................................................
cpu/x86/smm: SMM module loader version 2
Xeon-SP a Skylake Scalable Processor can have 36 CPU threads(18 cores). Current
coreboot SMM is unable to handle more than ~32 CPU threads. This patch
introduces a version 2 of the SMM module loader which addresses this problem.
Having two versions of the SMM module loader prevents any issues to current
projects. Future Xeon-SP products will be using this version of the SMM
loader. Subsequent patches will enable board specifc functionality
for Xeon-SP.
The reason for moving to version 2 is the state save area begins to encroach
upon the smi handling code when more than 32 CPU threads are in the system.
This can cause system hangs, reboots, etc. The second change is related to
staggered entry points with simple near jumps. In the current loader, near
jumps will not work because the CPU is jumping within the same code segment. In
version 2, "far" address jumps are necessary therefore protected mode must
is enabled first. The SMM layout and how the CPUs are staggered are documented
in the code.
By making the modifications above, this allows the smm module loader to expand
easily as more CPU threads are added.
TEST=build for Tiogapass platform under OCP mainboard. Enable the following in
Kconfig.
select CPU_INTEL_COMMON_SMM
select SOC_INTEL_COMMON_BLOCK_SMM
select SMM_TSEG
select HAVE_SMI_HANDLER
select ACPI_INTEL_HARDWARE_SLEEP_VALUES
Debug console will show all 36 cores relocated. Further tested by generating
SMI's to port 0xb2 using XDP/ITP HW debugger and ensured all cores entering
and exiting SMM properly. In addition, booted to Linux 5.4 kernel and observed
no issues during mp init.
Change-Id: I00a23a5f2a46110536c344254868390dbb71854c
Signed-off-by: Rocky Phagura <rphagura(a)fb.com>
---
M src/cpu/x86/Kconfig
M src/cpu/x86/smm/Makefile.inc
A src/cpu/x86/smm/smm_module_loaderv2.c
M src/include/cpu/x86/smm.h
4 files changed, 678 insertions(+), 0 deletions(-)
git pull ssh://review.coreboot.org:29418/coreboot refs/changes/84/43684/1
diff --git a/src/cpu/x86/Kconfig b/src/cpu/x86/Kconfig
index 5394cd0..b3a16bc 100644
--- a/src/cpu/x86/Kconfig
+++ b/src/cpu/x86/Kconfig
@@ -121,6 +121,14 @@
endif
+config X86_SMM_LOADER_VERSION2
+ bool
+ default n
+ depends on HAVE_SMI_HANDLER
+ help
+ This option enables SMM module loader that works with server
+ platforms which may contain more than 32 CPU threads.
+
config SMM_LAPIC_REMAP_MITIGATION
bool
default y if NORTHBRIDGE_INTEL_I945
diff --git a/src/cpu/x86/smm/Makefile.inc b/src/cpu/x86/smm/Makefile.inc
index dbe567a..1273a6c 100644
--- a/src/cpu/x86/smm/Makefile.inc
+++ b/src/cpu/x86/smm/Makefile.inc
@@ -1,6 +1,10 @@
## SPDX-License-Identifier: GPL-2.0-only
+ifeq ($(CONFIG_X86_SMM_LOADER_VERSION2),y)
+ramstage-y += smm_module_loaderv2.c
+else
ramstage-y += smm_module_loader.c
+endif
ramstage-y += smi_trigger.c
ifeq ($(CONFIG_ARCH_RAMSTAGE_X86_32),y)
diff --git a/src/cpu/x86/smm/smm_module_loaderv2.c b/src/cpu/x86/smm/smm_module_loaderv2.c
new file mode 100644
index 0000000..d1ccec0
--- /dev/null
+++ b/src/cpu/x86/smm/smm_module_loaderv2.c
@@ -0,0 +1,648 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+
+#include <string.h>
+#include <rmodule.h>
+#include <cpu/x86/smm.h>
+#include <commonlib/helpers.h>
+#include <console/console.h>
+#include <security/intel/stm/SmmStm.h>
+test
+#define FXSAVE_SIZE 512
+#define SMM_CODE_SEGMENT_SIZE 0x10000
+/* FXSAVE area during relocation. While it may not be strictly needed the
+ SMM stub code relies on the FXSAVE area being non-zero to enable SSE
+ instructions within SMM mode. */
+static uint8_t fxsave_area_relocation[CONFIG_MAX_CPUS][FXSAVE_SIZE]
+__attribute__((aligned(16)));
+
+/*
+ * Components that make up the SMRAM:
+ * 1. Save state - the total save state memory used
+ * 2. Stack - stacks for the CPUs in the SMM handler
+ * 3. Stub - SMM stub code for calling into handler
+ * 4. Handler - C-based SMM handler.
+ *
+ * The components are assumed to consist of one consecutive region.
+ */
+
+/* These parameters are used by the SMM stub code. A pointer to the params
+ * is also passed to the C-base handler. */
+struct smm_stub_params {
+ u32 stack_size;
+ u32 stack_top;
+ u32 c_handler;
+ u32 c_handler_arg;
+ u32 fxsave_area;
+ u32 fxsave_area_size;
+ struct smm_runtime runtime;
+} __packed;
+
+/*
+ * The stub is the entry point that sets up protected mode and stacks for each
+ * CPU. It then calls into the SMM handler module. It is encoded as an rmodule.
+ */
+extern unsigned char _binary_smmstub_start[];
+
+/* Per CPU minimum stack size. */
+#define SMM_MINIMUM_STACK_SIZE 32
+
+struct cpu_smm_info {
+ uint8_t active;
+ unsigned int smbase;
+ unsigned int entry;
+ unsigned int ss_start;
+ unsigned int code_start;
+ unsigned int code_end;
+};
+struct cpu_smm_info cpus[CONFIG_MAX_CPUS] = { 0 };
+
+/*
+ * This method creates a map of all the CPU entry points, save state locations
+ * and the beginning and end of code segments for each CPU. This map is used
+ * during relocation to properly align as many CPUs that can fit into the SMRAM
+ * region. For more information on how SMRAM works, refer to the latest Intel
+ * developer's manuals (volume 3, chapter 34). SMRAM is divided up into the
+ * following regions:
+ * +-----------------+ Top of SMRAM
+ * | | <- MSEG, FXSAVE
+ * +-----------------+
+ * | common |
+ * | smi handler | 64K
+ * | |
+ * +-----------------+
+ * | CPU 0 code seg |
+ * +-----------------+
+ * | CPU 1 code seg |
+ * +-----------------+
+ * | CPU x code seg |
+ * +-----------------+
+ * | |
+ * | |
+ * +-----------------+
+ * | stacks |
+ * +-----------------+ <- START of SMRAM
+ *
+ * The code below checks when a code segment is full and begins placing the remainder
+ * CPUs in the lower segments. The entry point for each CPU is smbase + 8000
+ * and save state is smbase + 0x8000 + (0x8000 - state save size). Save state
+ * area grows downward into the CPUs entry point. Therefore staggering too many
+ * CPUs in one 32K block will corrupt CPU0's entry code as the save states move
+ * downward.
+ * input : smbase of first CPU (all other CPUs
+ * will go below this address)
+ * input : num_cpus in the system. The map will
+ * be created from 0 to num_cpus.
+ */
+static int smm_create_map(unsigned int smbase, unsigned int num_cpus,
+ const struct smm_loader_params *params)
+{
+ unsigned int i;
+ struct rmodule smm_stub;
+ unsigned int ss_size = params->per_cpu_save_state_size, stub_size;
+ unsigned int smm_entry_offset = params->smm_main_entry_offset;
+ unsigned int seg_count = 0, segments = 0, available;
+ unsigned int cpus_in_segment = 0;
+ unsigned int base = smbase;
+
+ if (rmodule_parse(&_binary_smmstub_start, &smm_stub))
+ printk(BIOS_ERR, "%s : unable to get SMM module size\n", __func__);
+
+ stub_size = rmodule_memory_size(&smm_stub);
+ /* How many CPUs can fit into one segment? */
+ available = 0xFFFF - smm_entry_offset - ss_size - stub_size;
+ if (available > 0) {
+ cpus_in_segment = available/ss_size;
+ /* minimum segments needed will always be 1*/
+ segments = num_cpus / cpus_in_segment + 1;
+ printk(BIOS_DEBUG,
+ "%s: cpus in one segment %d\n", __func__, cpus_in_segment);
+ printk(BIOS_DEBUG,
+ "%s: min # of segments needed %d\n", __func__, segments);
+ } else {
+ printk(BIOS_ERR,
+ "%s: not enough space in SMM to setup all CPUs\n", __func__);
+ return -1;
+ }
+
+ if (sizeof(cpus)/sizeof(struct cpu_smm_info) < cpus_in_segment * segments) {
+ printk(BIOS_ERR,
+ "%s: more CPUs than originally configured for\n", __func__);
+ return -1;
+ }
+
+ for (i = 0; i < num_cpus; i++) {
+ cpus[i].smbase = base;
+ cpus[i].entry = base + smm_entry_offset;
+ cpus[i].ss_start = cpus[i].entry + (smm_entry_offset - ss_size);
+ cpus[i].code_start = cpus[i].entry;
+ cpus[i].code_end = cpus[i].entry + stub_size;
+ cpus[i].active = 1;
+ base -= ss_size;
+ seg_count++;
+ if (seg_count >= cpus_in_segment) {
+ base -= smm_entry_offset;
+ seg_count = 0;
+ }
+ }
+
+ if (CONFIG_DEFAULT_CONSOLE_LOGLEVEL >= BIOS_DEBUG) {
+ seg_count = 0;
+ for (i = 0; i < num_cpus; i++) {
+ printk(BIOS_DEBUG, "CPU 0x%x\n", i);
+ printk(BIOS_DEBUG,
+ " smbase 0x%x entry 0x%x\n",
+ cpus[i].smbase, cpus[i].entry);
+ printk(BIOS_DEBUG,
+ " ss_start 0x%x code_end 0x%x\n",
+ cpus[i].ss_start, cpus[i].code_end);
+ seg_count++;
+ if (seg_count >= cpus_in_segment) {
+ printk(BIOS_DEBUG,
+ "-------------NEW CODE SEGMENT --------------\n");
+ seg_count = 0;
+ }
+ }
+ }
+ return 1;
+}
+
+/*
+ * This method expects the smm relocation map to be complete.
+ * This method does not read any HW registers, it simply uses a
+ * map that was created during SMM setup.
+ * input: cpu_num - cpu number which is used as an index into the
+ * map to return the smbase
+ */
+int smm_get_cpu_smbase(unsigned int cpu_num)
+{
+ if (cpu_num < CONFIG_MAX_CPUS) {
+ if (cpus[cpu_num].active)
+ return cpus[cpu_num].smbase;
+ }
+ return 0;
+}
+
+/*
+ * This method assumes that at least 1 CPU has been set up from
+ * which it will place other CPUs below its smbase ensuring that
+ * save state does not clobber the first CPUs init code segment. The init
+ * code which is the smm stub code is the same for all CPUs. They enter
+ * smm, setup stacks (based on their apic id), enter protected mode
+ * and then jump to the common smi handler. The stack is allocated
+ * at the beginning of smram (aka tseg base, not smbase). The stack
+ * pointer for each CPU is calculated by using its apic id
+ * (code is in smm_stub.s)
+ * Each entry point will now have the same stub code which, sets up the CPU
+ * stack, enters protected mode and then jumps to the smi handler. It is
+ * important to enter protected mode before the jump because the "jump to
+ * address" might be larger than the 20bit address supported by real mode.
+ * SMI entry right now is in real mode.
+ * input: smbase - this is the smbase of the first cpu not the smbase
+ * where tseg starts (aka smram_start). All CPUs code segment
+ * and stack will be below this point except for the common
+ * SMI handler which is one segment above
+ * input: num_cpus - number of cpus that need relocation including
+ * the first CPU (though its code is already loaded)
+ * input: top of stack (stacks work downward by default in Intel HW)
+ * output: return -1, if runtime smi code could not be installed. In
+ * this case SMM will not work and any SMI's generated will
+ * cause a CPU shutdown or general protection fault becuause
+ * the appropriate smi handling code was not installed
+ */
+static void smm_place_entry_code(unsigned int smbase, unsigned int num_cpus,
+ unsigned int stack_top, const struct smm_loader_params *params)
+{
+ unsigned int i;
+ unsigned int size;
+ if (smm_create_map(smbase, num_cpus, params)) {
+ /*
+ * Ensure there was enough space and the last CPUs smbase
+ * did not encroach upon the stack. Stack top is smram start
+ * + size of stack.
+ */
+ if (cpus[num_cpus].active) {
+ if (cpus[num_cpus - 1].smbase +
+ params->smm_main_entry_offset < stack_top) {
+ printk(BIOS_ERR,
+ "%s : need more stack space, stack encroachment\n",
+ __func__);
+ printk(BIOS_ERR, "%s : smbase %x, stack_top %x\n",
+ __func__, cpus[num_cpus].smbase, stack_top);
+ return;
+ }
+ }
+ } else {
+ printk(BIOS_ERR, "%s : unable to place smm entry code\n", __func__);
+ return;
+ }
+
+ printk(BIOS_INFO, "%s : smbase %x, stack_top %x\n",
+ __func__, cpus[num_cpus-1].smbase, stack_top);
+
+ /* start at 1, the first CPU stub code is already there */
+ size = cpus[0].code_end - cpus[0].code_start;
+ for (i = 1; i < num_cpus; i++) {
+ memcpy((int *)cpus[i].code_start, (int *)cpus[0].code_start, size);
+ printk(BIOS_DEBUG,
+ "SMM Module: placing smm entry code at 0x%x, cpu # 0x%x\n",
+ cpus[i].code_start, i);
+ printk(BIOS_DEBUG, "%s copying from 0x%x to 0x%x 0x%x bytes\n",
+ __func__, cpus[0].code_start, cpus[i].code_start, size);
+ }
+ return;
+}
+
+/*
+ * Place stacks in base -> base + size region, but ensure the stacks don't
+ * overlap the staggered entry points.
+ */
+static void *smm_stub_place_stacks(char *base, size_t size,
+ struct smm_loader_params *params)
+{
+ size_t total_stack_size;
+ char *stacks_top;
+
+ /* If stack space is requested assume the space lives in the lower
+ * half of SMRAM. */
+ total_stack_size = params->per_cpu_stack_size *
+ params->num_concurrent_stacks;
+ printk(BIOS_DEBUG, "%s cpus: %x : stack space: needed -> %x\n",
+ __func__, (int)params->num_concurrent_stacks,
+ (int)total_stack_size);
+ printk(BIOS_DEBUG, " available -> %x : per_cpu_stack_size : %x\n",
+ (int)size, (int)params->per_cpu_stack_size);
+
+ /* There has to be at least one stack user. */
+ if (params->num_concurrent_stacks < 1)
+ return NULL;
+
+ /* Total stack size cannot fit. */
+ if (total_stack_size > size)
+ return NULL;
+
+ /* Stacks extend down to SMBASE */
+ stacks_top = &base[total_stack_size];
+ printk(BIOS_DEBUG, "%s : exit, stack_top %x\n", __func__, (int)stacks_top);
+
+ return stacks_top;
+}
+
+/*
+ * Place the staggered entry points for each CPU. The entry points are
+ * staggered by the per CPU SMM save state size extending down from
+ * SMM_ENTRY_OFFSET.
+ */
+static void smm_stub_place_staggered_entry_points(char *base,
+ const struct smm_loader_params *params, const struct rmodule *smm_stub)
+{
+ size_t stub_entry_offset;
+
+ stub_entry_offset = rmodule_entry_offset(smm_stub);
+ /* Each CPU now has its own stub code, which enters protected mode,
+ * sets up the stack, and then jumps to common SMI handler
+ */
+ if (params->num_concurrent_save_states > 1 || stub_entry_offset != 0) {
+ smm_place_entry_code((int)base, params->num_concurrent_save_states,
+ (int)params->stack_top, params);
+ }
+}
+
+/*
+ * The stub setup code assumes it is completely contained within the
+ * default SMRAM size (0x10000) for the default SMI handler (entry at
+ * 0x30000), but no assumption should be made for the permanent SMI handler.
+ * The placement of CPU entry points for permanent handler are determined
+ * by the number of CPUs in the system and the amount of SMRAM.
+ * There are potentially 3 regions to place
+ * within the default SMRAM size:
+ * 1. Save state areas
+ * 2. Stub code
+ * 3. Stack areas
+ *
+ * The save state and stack areas are treated as contiguous for the number of
+ * concurrent areas requested. The save state always lives at the top of the
+ * the CPUS smbase (and the entry point is at offset 0x8000. This allows only a certain
+ * number of CPUs with staggered entry points until the save state area comes
+ * down far enough to overwrite/corrupt the entry code (stub code). Therefore,
+ * an SMM map is created to avoid this corruption, see smm_create_map above.
+ * This module setup code works for the default SMM handler setup and the
+ * permanent SMM handler.
+ */
+static int smm_module_setup_stub(void *smbase, size_t smm_size,
+ struct smm_loader_params *params,
+ void *fxsave_area)
+{
+ size_t total_save_state_size;
+ size_t smm_stub_size;
+ size_t stub_entry_offset;
+ char *smm_stub_loc;
+ void *stacks_top;
+ size_t size;
+ char *base;
+ size_t i;
+ struct smm_stub_params *stub_params;
+ struct rmodule smm_stub;
+ unsigned int total_size_all;
+ base = smbase;
+ size = smm_size;
+
+ /* The number of concurrent stacks cannot exceed CONFIG_MAX_CPUS. */
+ if (params->num_concurrent_stacks > CONFIG_MAX_CPUS) {
+ printk(BIOS_ERR, "%s : not enough stacks\n", __func__);
+ return -1;
+ }
+
+ /* Fail if can't parse the smm stub rmodule. */
+ if (rmodule_parse(&_binary_smmstub_start, &smm_stub)) {
+ printk(BIOS_ERR, "%s : unable to parse smm stub\n", __func__);
+ return -1;
+ }
+
+ /* Adjust remaining size to account for save state. */
+ total_save_state_size = params->per_cpu_save_state_size *
+ params->num_concurrent_save_states;
+ if (total_save_state_size > size) {
+ printk(BIOS_ERR,
+ "%s:more state save space needed:need -> %x:available->%x\n",
+ __func__, (int)total_save_state_size, (int)size);
+ return -1;
+ }
+
+ size -= total_save_state_size;
+
+ /* The save state size encroached over the first SMM entry point. */
+ if (size <= params->smm_main_entry_offset) {
+ printk(BIOS_ERR, "%s:encroachment over SMM entry point\n", __func__);
+ printk(BIOS_ERR, "%s:state save size: %x : smm_entry_offset -> %x\n",
+ __func__, (int)size, params->smm_main_entry_offset);
+ return -1;
+ }
+
+ /* Need a minimum stack size and alignment. */
+ if (params->per_cpu_stack_size <= SMM_MINIMUM_STACK_SIZE ||
+ (params->per_cpu_stack_size & 3) != 0) {
+ printk(BIOS_ERR, "%s : need minimum stack size\n", __func__);
+ return -1;
+ }
+
+ smm_stub_loc = NULL;
+ smm_stub_size = rmodule_memory_size(&smm_stub);
+ stub_entry_offset = rmodule_entry_offset(&smm_stub);
+
+ /* Put the stub at at the main entry point */
+ smm_stub_loc = &base[params->smm_main_entry_offset];
+
+ /* Stub is too big to fit. */
+ if (smm_stub_size > (size - params->smm_main_entry_offset)) {
+ printk(BIOS_ERR, "%s : stub is too big to fit\n", __func__);
+ return -1;
+ }
+
+ /* The stacks, if requested, live in the lower half of SMRAM space
+ * for default handler, but for relocated handler it lives at the beginning
+ * of SMRAM which is TSEG base
+ */
+ size = params->num_concurrent_stacks*params->per_cpu_stack_size;
+ stacks_top = smm_stub_place_stacks((char *)params->smram_start, size, params);
+ if (stacks_top == NULL) {
+ printk(BIOS_ERR, "%s : not enough space for stacks\n", __func__);
+ printk(BIOS_ERR, "%s : ....need -> %x : available -> %x\n", __func__,
+ (int)base, (int)size);
+ return -1;
+ }
+ params->stack_top = stacks_top;
+ /* Load the stub. */
+ if (rmodule_load(smm_stub_loc, &smm_stub)) {
+ printk(BIOS_ERR, "%s : load module failed\n", __func__);
+ return -1;
+ }
+
+ smm_stub_place_staggered_entry_points(base, params, &smm_stub);
+
+ /* Setup the parameters for the stub code. */
+ stub_params = rmodule_parameters(&smm_stub);
+ stub_params->stack_top = (uintptr_t)stacks_top;
+ stub_params->stack_size = params->per_cpu_stack_size;
+ stub_params->c_handler = (uintptr_t)params->handler;
+ stub_params->c_handler_arg = (uintptr_t)params->handler_arg;
+ stub_params->fxsave_area = (uintptr_t)fxsave_area;
+ stub_params->fxsave_area_size = FXSAVE_SIZE;
+ stub_params->runtime.smbase = (uintptr_t)smbase;
+ stub_params->runtime.smm_size = smm_size;
+ stub_params->runtime.save_state_size = params->per_cpu_save_state_size;
+ stub_params->runtime.num_cpus = params->num_concurrent_stacks;
+
+ printk(BIOS_DEBUG, "%s : stack_end = 0x%x\n",
+ __func__, (int)stub_params->runtime.smbase);
+ printk(BIOS_DEBUG,
+ "%s : stack_top = 0x%x\n", __func__, (int)stub_params->stack_top);
+ printk(BIOS_DEBUG, "%s : stack_size = 0x%x\n",
+ __func__, (int)stub_params->stack_size);
+ printk(BIOS_DEBUG, "%s : runtime.smbase = 0x%x\n",
+ __func__, (int)stub_params->runtime.smbase);
+ printk(BIOS_DEBUG, "%s : runtime.start32_offset = 0x%x\n", __func__,
+ (int)stub_params->runtime.start32_offset);
+ printk(BIOS_DEBUG, "%s : runtime.smm_size = 0x%x\n",
+ __func__, (int)smm_size);
+ printk(BIOS_DEBUG, "%s : per_cpu_save_state_size = 0x%x\n",
+ __func__, (int)stub_params->runtime.save_state_size);
+ printk(BIOS_DEBUG, "%s : num_cpus = 0x%x\n", __func__,
+ (int)stub_params->runtime.num_cpus);
+ printk(BIOS_DEBUG, "%s : total_save_state_size = 0x%x\n",
+ __func__, (int)(stub_params->runtime.save_state_size*
+ stub_params->runtime.num_cpus));
+ total_size_all = (int)stub_params->stack_size +
+ (int)(stub_params->runtime.save_state_size*
+ stub_params->runtime.num_cpus);
+ printk(BIOS_DEBUG, "%s : total_size_all = 0x%x\n", __func__,
+ total_size_all);
+
+ /* Initialize the APIC id to CPU number table to be 1:1 */
+ for (i = 0; i < params->num_concurrent_stacks; i++)
+ stub_params->runtime.apic_id_to_cpu[i] = i;
+
+ /* Allow the initiator to manipulate SMM stub parameters. */
+ params->runtime = &stub_params->runtime;
+
+ printk(BIOS_DEBUG, "SMM Module: stub loaded at %p. Will call %p(%p)\n",
+ smm_stub_loc, params->handler, params->handler_arg);
+ return 0;
+}
+
+/*
+ * smm_setup_relocation_handler assumes the callback is already loaded in
+ * memory. i.e. Another SMM module isn't chained to the stub. The other
+ * assumption is that the stub will be entered from the default SMRAM
+ * location: 0x30000 -> 0x40000.
+ */
+int smm_setup_relocation_handler(struct smm_loader_params *params)
+{
+ void *smram = (void *)(SMM_DEFAULT_BASE);
+ printk(BIOS_SPEW, "%s: enter\n", __func__);
+ /* There can't be more than 1 concurrent save state for the relocation
+ * handler because all CPUs default to 0x30000 as SMBASE. */
+ if (params->num_concurrent_save_states > 1)
+ return -1;
+
+ /* A handler has to be defined to call for relocation. */
+ if (params->handler == NULL)
+ return -1;
+
+ /* Since the relocation handler always uses stack, adjust the number
+ * of concurrent stack users to be CONFIG_MAX_CPUS. */
+ if (params->num_concurrent_stacks == 0)
+ params->num_concurrent_stacks = CONFIG_MAX_CPUS;
+
+ params->smm_main_entry_offset = SMM_ENTRY_OFFSET;
+ params->smram_start = SMM_DEFAULT_BASE;
+ params->smram_end = SMM_DEFAULT_BASE + SMM_DEFAULT_SIZE;
+ return smm_module_setup_stub(smram, SMM_DEFAULT_SIZE,
+ params, fxsave_area_relocation);
+ printk(BIOS_SPEW, "%s: exit\n", __func__);
+}
+
+/*
+ *The SMM module is placed within the provided region in the following
+ * manner:
+ * +-----------------+ <- smram + size
+ * | BIOS resource |
+ * | list (STM) |
+ * +-----------------+
+ * | fxsave area |
+ * +-----------------+
+ * | smi handler |
+ * | ... |
+ * +-----------------+ <- cpu0
+ * | stub code | <- cpu1
+ * | stub code | <- cpu2
+ * | stub code | <- cpu3, etc
+ * | |
+ * | |
+ * | |
+ * | stacks |
+ * +-----------------+ <- smram start
+
+ * It should be noted that this algorithm will not work for
+ * SMM_DEFAULT_SIZE SMRAM regions such as the A segment. This algorithm
+ * expects a region large enough to encompass the handler and stacks
+ * as well as the SMM_DEFAULT_SIZE.
+ */
+int smm_load_module(void *smram, size_t size, struct smm_loader_params *params)
+{
+ struct rmodule smm_mod;
+ size_t total_stack_size;
+ size_t handler_size;
+ size_t module_alignment;
+ size_t alignment_size;
+ size_t fxsave_size;
+ void *fxsave_area;
+ size_t total_size = 0;
+ char *base;
+
+ if (size <= SMM_DEFAULT_SIZE)
+ return -1;
+
+ /* Load main SMI handler at the top of SMRAM
+ * everything else will go below
+ */
+ base = smram;
+ base += size;
+ params->smram_start = (uintptr_t)smram;
+ params->smram_end = params->smram_start + size;
+ params->smm_main_entry_offset = SMM_ENTRY_OFFSET;
+
+ /* Fail if can't parse the smm rmodule. */
+ if (rmodule_parse(&_binary_smm_start, &smm_mod))
+ return -1;
+
+ /* Clear SMM region */
+ if (CONFIG(DEBUG_SMI))
+ memset(smram, 0xcd, size);
+
+ total_stack_size = params->per_cpu_stack_size *
+ params->num_concurrent_stacks;
+ total_size += total_stack_size;
+ /* Stacks are the base of SMRAM */
+ params->stack_top = smram + total_stack_size;
+
+ /* MSEG starts at the top of SMRAM and works down */
+ if (CONFIG(STM)) {
+ base -= CONFIG_MSEG_SIZE + CONFIG_BIOS_RESOURCE_LIST_SIZE;
+ total_size += CONFIG_MSEG_SIZE + CONFIG_BIOS_RESOURCE_LIST_SIZE;
+ }
+
+ /* FXSAVE goes below MSEG */
+ if (CONFIG(SSE)) {
+ fxsave_size = FXSAVE_SIZE * params->num_concurrent_stacks;
+ fxsave_area = base - fxsave_size;
+ base -= fxsave_size;
+ total_size += fxsave_size;
+ } else {
+ fxsave_size = 0;
+ fxsave_area = NULL;
+ }
+
+
+ handler_size = rmodule_memory_size(&smm_mod);
+ base -= handler_size;
+ total_size += handler_size;
+ module_alignment = rmodule_load_alignment(&smm_mod);
+ alignment_size = module_alignment -
+ ((uintptr_t)base % module_alignment);
+ if (alignment_size != module_alignment) {
+ handler_size += alignment_size;
+ base += alignment_size;
+ }
+
+ printk(BIOS_DEBUG,
+ "%s : total_smm_space_needed 0x%x, available -> 0x%x\n",
+ __func__, (int)total_size, (int)size);
+
+ /* Does the required amount of memory exceed the SMRAM region size? */
+ if (total_size > size) {
+ printk(BIOS_ERR,
+ "%s : need more SMRAM\n", __func__);
+ return -1;
+ }
+ if (handler_size > SMM_CODE_SEGMENT_SIZE) {
+ printk(BIOS_ERR, "%s : increase SMM_CODE_SEGMENT_SIZE: handler_size = 0x%0x\n",
+ __func__, (int)handler_size);
+ return -1;
+ }
+
+ if (rmodule_load(base, &smm_mod))
+ return -1;
+
+ params->handler = rmodule_entry(&smm_mod);
+ params->handler_arg = rmodule_parameters(&smm_mod);
+
+ printk(BIOS_DEBUG, "%s : smram_start: 0x%x\n",
+ __func__, (int)smram);
+ printk(BIOS_DEBUG, "%s : smram_end: 0x%x\n",
+ __func__, (int)smram + (int)size);
+ printk(BIOS_DEBUG, "%s : stack_top: 0x%x\n",
+ __func__, (int)params->stack_top);
+ printk(BIOS_DEBUG, "%s : handler start 0x%x\n",
+ __func__, (int)params->handler);
+ printk(BIOS_DEBUG, "%s : handler_size 0x%x\n",
+ __func__, (int)handler_size);
+ printk(BIOS_DEBUG, "%s : handler_arg 0x%x\n",
+ __func__, (int)params->handler_arg);
+ printk(BIOS_DEBUG, "%s : fxsave_area 0x%x\n",
+ __func__, (int)fxsave_area);
+ printk(BIOS_DEBUG, "%s : fxsave_size 0x%x\n",
+ __func__, (int)fxsave_size);
+ printk(BIOS_DEBUG, "%s : CONFIG_MSEG_SIZE 0x%x\n",
+ __func__, (int)CONFIG_MSEG_SIZE);
+ printk(BIOS_DEBUG, "%s : CONFIG_BIOS_RESOURCE_LIST_SIZE 0x%x\n",
+ __func__, (int)CONFIG_BIOS_RESOURCE_LIST_SIZE);
+
+ /* CPU 0 smbase goes first, all other CPUs
+ * will be staggered below
+ */
+ base -= SMM_CODE_SEGMENT_SIZE;
+ printk(BIOS_DEBUG, "%s : cpu0 entry: 0x%x\n",
+ __func__, (int)base);
+ params->smm_entry = (uintptr_t)base + params->smm_main_entry_offset;
+ return smm_module_setup_stub(base, size, params, fxsave_area);
+}
diff --git a/src/include/cpu/x86/smm.h b/src/include/cpu/x86/smm.h
index a3101e5..7838223 100644
--- a/src/include/cpu/x86/smm.h
+++ b/src/include/cpu/x86/smm.h
@@ -128,6 +128,12 @@
* into this field so the code doing the loading can manipulate the
* runtime's assumptions. e.g. updating the APIC id to CPU map to
* handle sparse APIC id space.
+ * The following parameters are only used when X86_SMM_LOADER_VERSION2 is enabled.
+ * - smm_entry - entry address of first CPU thread, all others will be tiled
+ * below this address.
+ * - smm_main_entry_offset - default entry offset (e.g 0x8000)
+ * - smram_start - smaram starting address
+ * - smram_end - smram ending address
*/
struct smm_loader_params {
void *stack_top;
@@ -141,12 +147,24 @@
void *handler_arg;
struct smm_runtime *runtime;
+
+ /* The following are only used by X86_SMM_LOADER_VERSION2 */
+ #if CONFIG(X86_SMM_LOADER_VERSION2)
+ unsigned int smm_entry;
+ unsigned int smm_main_entry_offset;
+ unsigned int smram_start;
+ unsigned int smram_end;
+ #endif
};
/* Both of these return 0 on success, < 0 on failure. */
int smm_setup_relocation_handler(struct smm_loader_params *params);
int smm_load_module(void *smram, size_t size, struct smm_loader_params *params);
+#if CONFIG(X86_SMM_LOADER_VERSION2)
+int smm_get_cpu_smbase(unsigned int cpu_num);
+#endif
+
/* Backup and restore default SMM region. */
void *backup_default_smm_area(void);
void restore_default_smm_area(void *smm_save_area);
--
To view, visit https://review.coreboot.org/c/coreboot/+/43684
To unsubscribe, or for help writing mail filters, visit https://review.coreboot.org/settings
Gerrit-Project: coreboot
Gerrit-Branch: master
Gerrit-Change-Id: I00a23a5f2a46110536c344254868390dbb71854c
Gerrit-Change-Number: 43684
Gerrit-PatchSet: 1
Gerrit-Owner: Rocky Phagura
Gerrit-MessageType: newchange
Erin Lo has uploaded this change for review. ( https://review.coreboot.org/c/coreboot/+/34382 )
Change subject: WIP: mediatek/mt8183: Add SCP work support
......................................................................
WIP: mediatek/mt8183: Add SCP work support
Load SCP firmware to SCP's sram since buffer size is limited so load splitted binaries.
After SCP works done, disable it
Test=Build pass
Change-Id: I0801eac078aa9d6237142dcd92a3c3e9237a86ee
Signed-off-by: Erin Lo <erin.lo(a)mediatek.com>
---
M src/mainboard/google/kukui/Makefile.inc
M src/mainboard/google/kukui/romstage.c
M src/soc/mediatek/mt8183/Makefile.inc
M src/soc/mediatek/mt8183/include/soc/addressmap.h
A src/soc/mediatek/mt8183/include/soc/scp.h
A src/soc/mediatek/mt8183/scp.c
6 files changed, 123 insertions(+), 1 deletion(-)
git pull ssh://review.coreboot.org:29418/coreboot refs/changes/82/34382/1
diff --git a/src/mainboard/google/kukui/Makefile.inc b/src/mainboard/google/kukui/Makefile.inc
index a0556c1..f8a5bab 100644
--- a/src/mainboard/google/kukui/Makefile.inc
+++ b/src/mainboard/google/kukui/Makefile.inc
@@ -25,3 +25,18 @@
ramstage-y += mainboard.c
ramstage-y += memlayout.ld
ramstage-y += reset.c
+
+cbfs-files-y += scp_0.bin
+scp_0.bin-file := 3rdparty/blobs/mainboard/google/kukui/scp_0.bin
+scp_0.bin-type := raw
+scp_0.bin-compression := none
+
+cbfs-files-y += scp_1.bin
+scp_1.bin-file := 3rdparty/blobs/mainboard/google/kukui/scp_1.bin
+scp_1.bin-type := raw
+scp_1.bin-compression := none
+
+cbfs-files-y += scp_2.bin
+scp_2.bin-file := 3rdparty/blobs/mainboard/google/kukui/scp_2.bin
+scp_2.bin-type := raw
+scp_2.bin-compression := none
diff --git a/src/mainboard/google/kukui/romstage.c b/src/mainboard/google/kukui/romstage.c
index 1465243..cf3572d 100644
--- a/src/mainboard/google/kukui/romstage.c
+++ b/src/mainboard/google/kukui/romstage.c
@@ -19,7 +19,7 @@
#include <soc/mt6358.h>
#include <soc/pll.h>
#include <soc/rtc.h>
-
+#include <soc/scp.h>
#include "early_init.h"
void platform_romstage_main(void)
@@ -33,6 +33,7 @@
pmic_set_vsim2_cali(2700);
mt_pll_raise_ca53_freq(1989 * MHz);
rtc_boot();
+ scp_work();
mt_mem_init(get_sdram_config());
mtk_mmu_after_dram();
}
diff --git a/src/soc/mediatek/mt8183/Makefile.inc b/src/soc/mediatek/mt8183/Makefile.inc
index d35a07e..0543552 100644
--- a/src/soc/mediatek/mt8183/Makefile.inc
+++ b/src/soc/mediatek/mt8183/Makefile.inc
@@ -35,6 +35,7 @@
romstage-y += ../common/pll.c pll.c
romstage-y += ../common/pmic_wrap.c pmic_wrap.c mt6358.c
romstage-y += ../common/rtc.c rtc.c
+romstage-y += scp.c
romstage-$(CONFIG_SPI_FLASH) += ../common/spi.c spi.c
romstage-y += ../common/timer.c
romstage-y += ../common/uart.c
diff --git a/src/soc/mediatek/mt8183/include/soc/addressmap.h b/src/soc/mediatek/mt8183/include/soc/addressmap.h
index e9f80d1..affc776 100644
--- a/src/soc/mediatek/mt8183/include/soc/addressmap.h
+++ b/src/soc/mediatek/mt8183/include/soc/addressmap.h
@@ -34,6 +34,9 @@
EMI_BASE = IO_PHYS + 0x00219000,
EMI_MPU_BASE = IO_PHYS + 0x00226000,
DRAMC_CH_BASE = IO_PHYS + 0x00228000,
+ SCP_SRAM_BASE = IO_PHYS + 0x00500000,
+ SCP_CFG_BASE = IO_PHYS + 0x005C0000,
+ SCP_CLK_CTRL_BASE = IO_PHYS + 0x005C4000,
AUXADC_BASE = IO_PHYS + 0x01001000,
UART0_BASE = IO_PHYS + 0x01002000,
SPI0_BASE = IO_PHYS + 0x0100A000,
diff --git a/src/soc/mediatek/mt8183/include/soc/scp.h b/src/soc/mediatek/mt8183/include/soc/scp.h
new file mode 100644
index 0000000..a3003bd
--- /dev/null
+++ b/src/soc/mediatek/mt8183/include/soc/scp.h
@@ -0,0 +1,36 @@
+/*
+ * This file is part of the coreboot project.
+ *
+ * Copyright 2019 MediaTek 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.
+ */
+
+#ifndef SOC_MEDIATEK_MT8183_SCP_H
+#define SOC_MEDIATEK_MT8183_SCP_H
+
+#include <soc/addressmap.h>
+#include <types.h>
+
+struct mt8183_scp_regs {
+ u32 sw_rstn;
+ u32 reserved[19];
+ u32 gpr0;
+};
+
+struct mt8183_scp_clk_ctrl_regs {
+ u32 reserved[11];
+ u32 sram_pdn;
+};
+
+static struct mt8183_scp_regs *const mt8183_scp = (void *)SCP_CFG_BASE;
+static struct mt8183_scp_clk_ctrl_regs *const mt8183_scp_clk_ctrl = (void *)SCP_CLK_CTRL_BASE;
+void scp_work(void);
+#endif /* SOC_MEDIATEK_MT8183_SCP_H */
diff --git a/src/soc/mediatek/mt8183/scp.c b/src/soc/mediatek/mt8183/scp.c
new file mode 100644
index 0000000..150eeba
--- /dev/null
+++ b/src/soc/mediatek/mt8183/scp.c
@@ -0,0 +1,66 @@
+/*
+ * This file is part of the coreboot project.
+ *
+ * Copyright 2019 MediaTek 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.
+ */
+
+#include <arch/barrier.h>
+#include <cbfs.h>
+#include <console/console.h>
+#include <arch/mmio.h>
+#include <soc/scp.h>
+#include <string.h>
+
+#define BUF_SIZE (40 * KiB)
+static uint8_t scp_bin[BUF_SIZE] __aligned(8);
+
+void scp_work(void)
+{
+ size_t fw_size;
+
+ write32(&mt8183_scp_clk_ctrl->sram_pdn, 0x0);
+ mb();
+
+ fw_size = cbfs_boot_load_file("scp_0.bin",
+ scp_bin,
+ sizeof(scp_bin),
+ CBFS_TYPE_RAW);
+ if (fw_size == 0)
+ die("SCP file :scp_0.bin not found.");
+ memcpy((void *)SCP_SRAM_BASE + 0x0, scp_bin, fw_size);
+
+ fw_size = cbfs_boot_load_file("scp_1.bin",
+ scp_bin,
+ sizeof(scp_bin),
+ CBFS_TYPE_RAW);
+ memcpy((void *)SCP_SRAM_BASE + BUF_SIZE, scp_bin, fw_size);
+ if (fw_size == 0)
+ die("SCP file :scp_1.bin not found.");
+
+ fw_size = cbfs_boot_load_file("scp_2.bin",
+ scp_bin,
+ sizeof(scp_bin),
+ CBFS_TYPE_RAW);
+ if (fw_size == 0)
+ die("SCP file :scp_2.bin not found.");
+ memcpy((void *)SCP_SRAM_BASE + BUF_SIZE*2, scp_bin, fw_size);
+
+
+ /* Memory barrier to ensure that all fw code is loaded
+ before we release the reset pin. */
+ mb();
+ write32(&mt8183_scp->sw_rstn, 0x1);
+ while (read32(&mt8183_scp->gpr0) != 0xaaaa){}
+ mb();
+ write32(&mt8183_scp->sw_rstn, 0x0);
+ printk(BIOS_DEBUG, "scp finished \n");
+}
--
To view, visit https://review.coreboot.org/c/coreboot/+/34382
To unsubscribe, or for help writing mail filters, visit https://review.coreboot.org/settings
Gerrit-Project: coreboot
Gerrit-Branch: master
Gerrit-Change-Id: I0801eac078aa9d6237142dcd92a3c3e9237a86ee
Gerrit-Change-Number: 34382
Gerrit-PatchSet: 1
Gerrit-Owner: Erin Lo <erin.lo(a)mediatek.com>
Gerrit-MessageType: newchange
Jeremy Soller has uploaded this change for review. ( https://review.coreboot.org/c/coreboot/+/35946 )
Change subject: driver/thunderbolt: Driver for allocating hotplug resources
......................................................................
driver/thunderbolt: Driver for allocating hotplug resources
This adds a new driver which can be selected with DRIVERS_THUNDERBOLT
that, by default, adds 32 PCI subordinate numbers, 256 MiB of both
prefetchable and non-prefetchable memory, and 8 KiB of I/O space to
matching devices. It currently supports the JHL7540 Thunderbolt 3
bridge, but other devices can be added easily.
In order to support the allocation of hotplugged PCI buses, a new field
was added to struct device called hotplug_buses. This is defaulted to
zero, but when set, it adds the hotplug_buses value to the subordinate
value of the PCI bridge. This allows devices to be plugged in and
unplugged after boot.
This code was tested on the System76 Darter Pro (darp6). Before this
change, there are not enough resources allocated to the Thunderbolt
PCI bridge to allow plugging in new devices after boot. This can be
worked around in the Linux kernel by passing a boot param such as:
pci=assign-buses,hpbussize=32,realloc
This change makes it possible to use Thunderbolt hotplugging without
kernel parameters, and attempts to match closely what our motherboard
manufacturer's firmware does by default.
Signed-off-by: Jeremy Soller <jeremy(a)system76.com>
Change-Id: I500191626584b83e6a8ae38417fd324b5e803afc
---
M src/device/pci_device.c
A src/drivers/thunderbolt/Kconfig
A src/drivers/thunderbolt/Makefile.inc
A src/drivers/thunderbolt/thunderbolt.c
M src/include/device/device.h
5 files changed, 117 insertions(+), 1 deletion(-)
git pull ssh://review.coreboot.org:29418/coreboot refs/changes/46/35946/1
diff --git a/src/device/pci_device.c b/src/device/pci_device.c
index c043dd6..1796d81 100644
--- a/src/device/pci_device.c
+++ b/src/device/pci_device.c
@@ -1217,7 +1217,7 @@
if (state == PCI_ROUTE_SCAN) {
link->secondary = parent->subordinate + 1;
- link->subordinate = link->secondary;
+ link->subordinate = link->secondary + dev->hotplug_buses;
}
if (state == PCI_ROUTE_CLOSE) {
diff --git a/src/drivers/thunderbolt/Kconfig b/src/drivers/thunderbolt/Kconfig
new file mode 100644
index 0000000..f64e6cb
--- /dev/null
+++ b/src/drivers/thunderbolt/Kconfig
@@ -0,0 +1,4 @@
+config DRIVERS_THUNDERBOLT
+ bool
+ help
+ Thunderbolt support
diff --git a/src/drivers/thunderbolt/Makefile.inc b/src/drivers/thunderbolt/Makefile.inc
new file mode 100644
index 0000000..623b897
--- /dev/null
+++ b/src/drivers/thunderbolt/Makefile.inc
@@ -0,0 +1 @@
+ramstage-$(CONFIG_DRIVERS_THUNDERBOLT) += thunderbolt.c
diff --git a/src/drivers/thunderbolt/thunderbolt.c b/src/drivers/thunderbolt/thunderbolt.c
new file mode 100644
index 0000000..db463e0e
--- /dev/null
+++ b/src/drivers/thunderbolt/thunderbolt.c
@@ -0,0 +1,110 @@
+/*
+ * This file is part of the coreboot project.
+ *
+ * Copyright (C) 2019 System76.
+ * Copyright (C) 2017-2018 Intel Corporation.
+ *
+ * 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 <console/console.h>
+#include <device/device.h>
+#include <device/pci.h>
+#include <device/pciexp.h>
+#include <device/pci_def.h>
+#include <device/pci_ids.h>
+#include <device/pci_ops.h>
+
+static void slot_dev_read_resources(struct device *dev)
+{
+ struct resource *resource;
+
+ // Add 256 MiB of memory space
+ resource = new_resource(dev, 0x10);
+ resource->size = 1 << 28;
+ resource->align = 22;
+ resource->gran = 22;
+ resource->limit = 0xffffffff;
+ resource->flags |= IORESOURCE_MEM;
+
+ // Add 256 MiB of prefetchable memory space
+ resource = new_resource(dev, 0x14);
+ resource->size = 1 << 28;
+ resource->align = 22;
+ resource->gran = 22;
+ resource->limit = 0xffffffff;
+ resource->flags |= IORESOURCE_MEM | IORESOURCE_PREFETCH;
+
+ // Add 8 KiB of I/O space
+ resource = new_resource(dev, 0x18);
+ resource->size = 1 << 13;
+ resource->align = 12;
+ resource->gran = 12;
+ resource->limit = 0xffff;
+ resource->flags |= IORESOURCE_IO;
+}
+
+static struct device_operations slot_dev_ops = {
+ .read_resources = slot_dev_read_resources,
+};
+
+static bool tbt_is_hotplug_bridge(struct device *dev) {
+ return PCI_SLOT(dev->path.pci.devfn) == 1;
+}
+
+static void tbt_pciexp_scan_bridge(struct device *dev) {
+ printk(BIOS_DEBUG, "%s: %s: scan bridge\n", __func__, dev_path(dev));
+
+ bool is_hotplug = tbt_is_hotplug_bridge(dev);
+ if (is_hotplug) {
+ /* Add hotplug buses, must happen before bus scan */
+ printk(BIOS_DEBUG, "%s: %s: add hotplug buses\n", __func__, dev_path(dev));
+ dev->hotplug_buses = 32;
+ }
+
+ /* Normal PCIe Scan */
+ pciexp_scan_bridge(dev);
+
+ if (is_hotplug) {
+ /* Add dummy slot to preserve resources, must happen after bus scan */
+ printk(BIOS_DEBUG, "%s: %s: add dummy device\n", __func__, dev_path(dev));
+ struct device *slot;
+ struct device_path slot_path = { .type = DEVICE_PATH_NONE };
+ slot = alloc_dev(dev->link_list, &slot_path);
+ slot->ops = &slot_dev_ops;
+ }
+}
+
+static struct pci_operations pcie_ops = {
+ .set_subsystem = pci_dev_set_subsystem,
+};
+
+static struct device_operations device_ops = {
+ .read_resources = pci_bus_read_resources,
+ .set_resources = pci_dev_set_resources,
+ .enable_resources = pci_bus_enable_resources,
+ .init = 0,
+ .scan_bus = tbt_pciexp_scan_bridge,
+ .enable = 0,
+ .reset_bus = pci_bus_reset,
+ .ops_pci = &pcie_ops,
+};
+
+static const unsigned short pcie_device_ids[] = {
+ // JHL7540 Thunderbolt 3 Bridge
+ 0x15e7,
+ 0
+};
+
+static const struct pci_driver tbt_pcie __pci_driver = {
+ .ops = &device_ops,
+ .vendor = PCI_VENDOR_ID_INTEL,
+ .devices = pcie_device_ids,
+};
diff --git a/src/include/device/device.h b/src/include/device/device.h
index cb37c09..f22bed5 100644
--- a/src/include/device/device.h
+++ b/src/include/device/device.h
@@ -129,6 +129,7 @@
unsigned int disable_pcie_aspm : 1;
unsigned int hidden : 1; /* set if we should hide from UI */
u8 command;
+ uint16_t hotplug_buses; /* hotplug buses to allocate */
/* Base registers for this device. I/O, MEM and Expansion ROM */
DEVTREE_CONST struct resource *resource_list;
--
To view, visit https://review.coreboot.org/c/coreboot/+/35946
To unsubscribe, or for help writing mail filters, visit https://review.coreboot.org/settings
Gerrit-Project: coreboot
Gerrit-Branch: master
Gerrit-Change-Id: I500191626584b83e6a8ae38417fd324b5e803afc
Gerrit-Change-Number: 35946
Gerrit-PatchSet: 1
Gerrit-Owner: Jeremy Soller <jeremy(a)system76.com>
Gerrit-MessageType: newchange