Compare commits

...
Sign in to create a new pull request.

67 commits

Author SHA1 Message Date
Paul Menzel
046814c270 Makefile.inc: Decrease minimal pagesize from 4 kB to 1 kB
GCC 12 incorrectly warns about an array out of bounds issue:

```
$ make V=1 # emulation/qemu-i440fx
[…]
    CC         ramstage/arch/x86/ebda.o
x86_64-linux-gnu-gcc-12 -MMD -Isrc -Isrc/include -Isrc/commonlib/include -Isrc/commonlib/bsd/include -Ibuild -I3rdparty/vboot/firmware/include -include src/include/kconfig.h -include src/include/rules.h -include src/commonlib/bsd/include/commonlib/bsd/compiler.h -I3rdparty -D__BUILD_DIR__=\"build\" -Isrc/arch/x86/include -D__ARCH_x86_32__ -pipe -g -nostdinc -std=gnu11 -nostdlib -Wall -Wundef -Wstrict-prototypes -Wmissing-prototypes -Wwrite-strings -Wredundant-decls -Wno-trigraphs -Wimplicit-fallthrough -Wshadow -Wdate-time -Wtype-limits -Wvla -Wdangling-else -fno-common -ffreestanding -fno-builtin -fomit-frame-pointer -fstrict-aliasing -ffunction-sections -fdata-sections -fno-pie -Wno-packed-not-aligned -fconserve-stack -Wnull-dereference -Wreturn-type -Wlogical-op -Wduplicated-cond -Wno-unused-but-set-variable -Werror -Os -Wno-address-of-packed-member -m32 -Wl,-b,elf32-i386 -Wl,-melf_i386 -m32  -fuse-ld=bfd -fno-stack-protector -Wl,--build-id=none -fno-delete-null-pointer-checks -Wlogical-op -march=i686 -mno-mmx -MT build/ramstage/arch/x86/ebda.o -D__RAMSTAGE__ -c -o build/ramstage/arch/x86/ebda.o src/arch/x86/ebda.c
In file included from src/arch/x86/ebda.c:6:
In function 'write_ble8',
    inlined from 'write_le8' at src/commonlib/include/commonlib/endian.h:155:2,
    inlined from 'write_le16' at src/commonlib/include/commonlib/endian.h:178:2,
    inlined from 'setup_ebda' at src/arch/x86/ebda.c:35:2,
    inlined from 'setup_default_ebda' at src/arch/x86/ebda.c:48:2:
src/commonlib/include/commonlib/endian.h:27:26: error: array subscript 0 is outside array bounds of 'void[0]' [-Werror=array-bounds]
   27 |         *(uint8_t *)dest = val;
      |         ~~~~~~~~~~~~~~~~~^~~~~
[…]
```

[In GCC 12 the new parameter `min-pagesize` is added and defaults 4 kB.][1]
It treats INTEGER_CST addresses smaller than that as assumed results of
pointer arithmetics from NULL while addresses equal or larger than that
as expected user constant addresses. For GCC 13 we can represent results
from pointer arithmetics on NULL using &MEM[(void*)0 + offset] instead
of (void*)offset INTEGER_CSTs.

[1]: https://web.archive.org/web/20220711061810/https://gcc.gnu.org/bugzilla/show_bug.cgi?id=99578

TEST=No compile error with gcc (Debian 12.2.0-3) 12.2.0
Change-Id: I6e36633f42cb4dc5af53212c10c919a86e451ee0
Original-Signed-off-by: Paul Menzel <pmenzel@molgen.mpg.de>
Original-Reviewed-on: https://review.coreboot.org/c/coreboot/+/62830
Original-Tested-by: build bot (Jenkins) <no-reply@coreboot.org>
Original-Reviewed-by: Angel Pons <th3fanbus@gmail.com>
Reviewed-on: https://review.coreboot.org/c/coreboot/+/81785
Tested-by: Felix Singer <service+coreboot-gerrit@felixsinger.de>
Reviewed-by: Felix Singer <service+coreboot-gerrit@felixsinger.de>
Reviewed-by: Angel Pons <th3fanbus@gmail.com>
2024-04-11 15:48:30 +00:00
Eugene Myers
1c13f8d85c security/intel/stm/Makefile.inc: Fix typo
In both the Kconfig and Makefile in this directory,
"STM_TTYS0_BASE" is used. Therefore, fix the typo.

Original-Change-Id: Ie83ec31c7bb0f6805c0225ee7405e137a666a5d3
Original-Signed-off-by: Benjamin Doron <benjamin.doron00@gmail.com>
Original-Reviewed-on: https://review.coreboot.org/c/coreboot/+/51206
Original-Reviewed-by: Angel Pons <th3fanbus@gmail.com>
Original-Reviewed-by: Eugene Myers <cedarhouse1@comcast.net>
Original-Tested-by: build bot (Jenkins) <no-reply@coreboot.org>

Change-Id: I8aa81a51380d48b172284e534ffd203f30a10286
Signed-off-by: Eugene Myers <edmyers@tycho.nsa.gov>
Reviewed-on: https://review.coreboot.org/c/coreboot/+/55624
Reviewed-by: Stefan Reinauer <stefan.reinauer@coreboot.org>
Tested-by: build bot (Jenkins) <no-reply@coreboot.org>
2023-06-10 07:22:29 +00:00
Eugene Myers
92c1a19c79 security/intel/stm: Provide MSEG too small diagnostic information
This patch provides diagnostic information during the STM setup to
indicate when the MSEG is too small for what the STM requires.
The error message includes the configured MSEG size and the MSEG
area that the STM needs.

Change-Id: I88d947e3a0495089be886f6557e4d4d7993e2508
Signed-off-by: Eugene Myers <edmyers@tycho.nsa.gov>
Reviewed-on: https://review.coreboot.org/c/coreboot/+/55630
Tested-by: build bot (Jenkins) <no-reply@coreboot.org>
Reviewed-by: Stefan Reinauer <stefan.reinauer@coreboot.org>
2023-06-10 03:21:48 +00:00
Eugene Myers
34010e8adb security/intel/stm: Make sure stm_resource_heap is consistent
When a parallel SMM relocation is being done, there is a good chance
that the value for stm_resource_heap is not consistent across processors.
Rather than holding (via a lock) processors until this value is set and
then flushing the cache so that all processors see the same value, this
solution moves the code such that all processors set it, thus maintaining
parallelism and keeping the code simple.

Change-Id: I2e5385c47124adcd99803337167984b6307af860
Signed-off-by: Eugene Myers <edmyers@tycho.nsa.gov>
Reviewed-on: https://review.coreboot.org/c/coreboot/+/55629
Tested-by: build bot (Jenkins) <no-reply@coreboot.org>
Reviewed-by: Stefan Reinauer <stefan.reinauer@coreboot.org>
2023-06-10 03:21:23 +00:00
Eugene Myers
e7e2bd2a59 cpu/x86/: Centralize MSEG location calculation
This patch centralizes the MSEG location calculation. In the current
implementation, the calculation happens in smm_module_loader and
mp_init.  When smm_module_loaderv2 was added, this calculation became
broken as the original calculation made assumptions based on perm_smbase.

The calculation is now located in smm_subregion (tseg_region.c), as the
MSEG is located within the TSEG (or SMM);

These patches have been tested on a Purism librem-l1um server.

Change-Id: Ic17e1a505401c3b2a218826dffae6fe12a5c15c6
Signed-off-by: Eugene Myers <edmyers@tycho.nsa.gov>
Reviewed-on: https://review.coreboot.org/c/coreboot/+/55628
Reviewed-by: Stefan Reinauer <stefan.reinauer@coreboot.org>
Tested-by: build bot (Jenkins) <no-reply@coreboot.org>
2023-06-10 03:21:08 +00:00
Eugene Myers
0f93a91548 security/intel/stm: Reset BIOS resource list on every stm_setup call
Some platforms run the smm_relocation function twice during initialization.
This results in the BIOS resource list becoming twice as long.  Also,
testing has shown that elements of the list created in the first interation
may have invalid data included in the resource list.

This patch resolves these issues by reseting the list every time stm_setup
is involked.

This patch has been tested on the Purism L1UM-1X8C

Change-Id: I874871ff01bdf0d00a3e6b48bc885e7abaa25112
Signed-off-by: Eugene Myers <edmyers@tycho.nsa.gov>
Reviewed-on: https://review.coreboot.org/c/coreboot/+/55627
Tested-by: build bot (Jenkins) <no-reply@coreboot.org>
Reviewed-by: Stefan Reinauer <stefan.reinauer@coreboot.org>
2023-06-10 03:20:56 +00:00
Eugene Myers
56ce49f10f soc/intel/fsp_broadwell_de: Enable STM for broadwell_de
This patch enables the STM for broadwell_de by setting CONFIG_VMX

Change-Id: I8292bb4eec516556ad1ba658c80ad8a0b541139f
Signed-off-by: Eugene Myers <edmyers@tycho.nsa.gov>
Reviewed-on: https://review.coreboot.org/c/coreboot/+/55626
Tested-by: build bot (Jenkins) <no-reply@coreboot.org>
Reviewed-by: Stefan Reinauer <stefan.reinauer@coreboot.org>
2023-06-10 03:20:43 +00:00
Eugene Myers
75c35288d8 3rdparty: Add STM as a submodule
The patch incorporates the STM build as a part of the coreboot
build.  A separate patch lists and documents the options that
the developer can use.  In most cases the default options will
suffice.

Original-Change-Id: I8c6e0c85edd4e2b0658791553bd9947656e8c796
Original-Signed-off-by: Eugene D Myers <cedarhouse@comcast.net>
Original-Reviewed-on: https://review.coreboot.org/c/coreboot/+/44687
Original-Tested-by: build bot (Jenkins) <no-reply@coreboot.org>
Original-Reviewed-by: ron minnich <rminnich@gmail.com>

Change-Id: I901cb429d8050fb2a7c839e8ef29ac3359239d2c
Signed-off-by: Eugene Myers <edmyers@tycho.nsa.gov>
Reviewed-on: https://review.coreboot.org/c/coreboot/+/55625
Reviewed-by: Stefan Reinauer <stefan.reinauer@coreboot.org>
Tested-by: build bot (Jenkins) <no-reply@coreboot.org>
2023-06-10 03:20:32 +00:00
Eugene Myers
701180f069 security/intel/stm/SmmStm.c: Fix size_t printf format error
Replaced the 'l' with a 'z' to clear up the issue.

Change-Id: I696b615b4dd3bacda7151c91fff17f9b01b17821
Signed-off-by: Eugene Myers <edmyers@tycho.nsa.gov>
Reviewed-on: https://review.coreboot.org/c/coreboot/+/55623
Reviewed-by: Stefan Reinauer <stefan.reinauer@coreboot.org>
Tested-by: build bot (Jenkins) <no-reply@coreboot.org>
2023-06-10 03:20:21 +00:00
Eugene Myers
2b32db6ddc security/intel/stm: Add options for STM build
This patch adds options that support building the STM as a
part of the coreboot build.  The option defaults assume that
these configuration options are set as follows:

      IED_REGION_SIZE   = 0x400000
      SMM_RESERVED_SIZE = 0x200000
      SMM_TSEG_SIZE     = 0x800000

Original-Change-Id: I80ed7cbcb93468c5ff93d089d77742ce7b671a37
Original-Signed-off-by: Eugene Myers <cedarhouse@comcast.net>
Original-Reviewed-on: https://review.coreboot.org/c/coreboot/+/44686
Original-Tested-by: build bot (Jenkins) <no-reply@coreboot.org>
Original-Reviewed-by: ron minnich <rminnich@gmail.com>

Change-Id: I982cde1299c87b5cf4f495905b53a6c107842956
Signed-off-by: Eugene Myers <edmyers@tycho.nsa.gov>
Reviewed-on: https://review.coreboot.org/c/coreboot/+/55622
Tested-by: build bot (Jenkins) <no-reply@coreboot.org>
Reviewed-by: Stefan Reinauer <stefan.reinauer@coreboot.org>
2023-06-10 03:20:07 +00:00
Eugene Myers
60004e276a soc/intel: Add get_pmbase
Originally a part of security/intel/stm.

Add get_pmbase to the intel platform setup code.

get_pmbase is used by the coreboot STM setup functions to ensure
that the pmbase is accessable by the SMI handler during runtime.
The pmbase has to be accounted for in the BIOS resource list so
that the SMI handler is allowed this access.

Original-Change-Id: If6f6295c5eba9eb20e57ab56e7f965c8879e93d2
Original-Signed-off-by: Eugene D. Myers <edmyers@tycho.nsa.gov>
Original-Reviewed-on: https://review.coreboot.org/c/coreboot/+/37990
Original-Reviewed-by: Patrick Georgi <pgeorgi@google.com>
Original-Tested-by: build bot (Jenkins) <no-reply@coreboot.org>

Change-Id: I7f9ef32946a17aa0bbcbc375bc34b48e62620694
Signed-off-by: Eugene Myers <edmyers@tycho.nsa.gov>
Reviewed-on: https://review.coreboot.org/c/coreboot/+/55621
Tested-by: build bot (Jenkins) <no-reply@coreboot.org>
Reviewed-by: Stefan Reinauer <stefan.reinauer@coreboot.org>
2023-06-10 03:19:55 +00:00
Iru Cai
6ffb50080a Makefile.inc: Replace linker flag -nostartfiles with --nmagic
While the gcc(1) driver has the `-nostartfiles` option, ld(1), the
program the coreboot toolchain uses to link the object files, doesn't
have it.

In binutils before 2.36, this option is interpreted as `-n -o
startfiles`, in which the `-o` option is overridden by a later `-o`
option, so only the `-n` option has effect, which is the `--nmagic`
long option of ld(1). So the correct linker option in this place is
`--nmagic`.

It is tested that without `--nmagic`, ld can generate a much bigger
x86_64 romstage, so this option is still needed.

This error is found when trying to update binutils to 2.36 and later
versions, where ld(1) is unable to disambiguate options and reports an
error.

Change-Id: I27dc2209abdc6fec866716a252736c5cf236a347
Signed-off-by: Iru Cai <mytbk920423@gmail.com>
Reviewed-on: https://review.coreboot.org/c/coreboot/+/56490
Tested-by: build bot (Jenkins) <no-reply@coreboot.org>
Reviewed-by: Martin Roth <martinroth@google.com>
Signed-off-by: Uwe Poeche <uwe.poeche@siemens.com>
Reviewed-on: https://review.coreboot.org/c/coreboot/+/61958
Reviewed-by: Werner Zeh <werner.zeh@siemens.com>
Reviewed-by: Elyes Haouas <ehaouas@noos.fr>
2022-02-22 15:26:23 +00:00
Marc Jones
4401498041 Documentation: Add OCP Mono Lake mainboard
Add information about the OCP Mono Lake mainboard.

Change-Id: I2109cca0e4037a2945bcb7e4d80897b48ada54af
Signed-off-by: Marc Jones <marcjones@sysproconsutling.com>
Reviewed-on: https://review.coreboot.org/c/coreboot/+/57561
Reviewed-by: Stefan Reinauer <stefan.reinauer@coreboot.org>
Reviewed-by: Jay Talbott <JayTalbott@sysproconsulting.com>
Tested-by: Stefan Reinauer <stefan.reinauer@coreboot.org>
Tested-by: build bot (Jenkins) <no-reply@coreboot.org>
2021-10-04 18:41:50 +00:00
Marc Jones
40dccd9f36 mainboard/ocp/monolake: Give the BMC time to startup
Set bmc_boot_timeout and wait_for_bmc to give the BMC more time to respond
before coreboot times out and moves on. Passes IPMI BMC selftest.

Change-Id: I310a08b8c134cf839381675ade2fe7deee9b1909
Signed-off-by: Marc Jones <marcj303@gmail.com>
Reviewed-on: https://review.coreboot.org/c/coreboot/+/55770
Reviewed-by: Martin Roth <martinroth@google.com>
Reviewed-by: Jay Talbott <JayTalbott@sysproconsulting.com>
Tested-by: build bot (Jenkins) <no-reply@coreboot.org>
2021-06-25 06:30:11 +00:00
Johnny Lin
2953527a67 drivers/ipmi: Add CONFIG_IPMI_KCS_TIMEOUT_MS for IPMI KCS timeout value
With the current timeout of 1000 cycles of 100 microsecond would see
timeout occurs on OCP Delta Lake if the log level is set to values
smaller than 8. Because the prink(BIOS_SPEW, ..) in ipmi_kcs_status()
creates delay and avoid the problem, but after setting the log level
to 4 we see some timeout occurs.

The unit is millisecond and the default value is set to 5000 according
to IPMI spec v2.0 rev 1.1 Sec. 9.15, a five-second timeout or greater
is recommended.

Tested=On OCP Delta Lake, with log level 4 cannot observe timeout
occurs.

Original-Change-Id: I42ede1d9200bb5d0dbb455d2ff66e2816f10e86b
Original-Signed-off-by: Johnny Lin <johnny_lin@wiwynn.com>
Original-Reviewed-on: https://review.coreboot.org/c/coreboot/+/45103
Original-Reviewed-by: Patrick Georgi <pgeorgi@google.com>
Original-Reviewed-by: Angel Pons <th3fanbus@gmail.com>
Original-Reviewed-by: Paul Menzel <paulepanter@users.sourceforge.net>
Original-Tested-by: build bot (Jenkins) <no-reply@coreboot.org>
(cherry picked from commit d04c06b472)

Change-Id: I7046467d41e1feddb07081964466c8189321cb1d
Signed-off-by: Marc Jones <marcj303@gmail.com>
Reviewed-on: https://review.coreboot.org/c/coreboot/+/55769
Reviewed-by: Martin Roth <martinroth@google.com>
Reviewed-by: Jay Talbott <JayTalbott@sysproconsulting.com>
Tested-by: build bot (Jenkins) <no-reply@coreboot.org>
2021-06-25 04:13:31 +00:00
Jacob Garber
e7a126fbc2 drivers/ipmi: Fix buffer double-free
If reading the data for the asset_tag fails, that buffer should be
freed, not the one for serial_number.

Original-Change-Id: I2ecaf7fd0f23f2fb5a6aa0961c7e17fff04847f4
Original-Signed-off-by: Jacob Garber <jgarber1@ualberta.ca>
Original-Found-by: Coverity CID 1419481, 1419485
Original-Reviewed-on: https://review.coreboot.org/c/coreboot/+/39378
Original-Tested-by: build bot (Jenkins) <no-reply@coreboot.org>
Original-Reviewed-by: Paul Menzel <paulepanter@users.sourceforge.net>
Original-Reviewed-by: Patrick Rudolph <siro@das-labor.org>
Original-Reviewed-by: Angel Pons <th3fanbus@gmail.com>
(cherry picked from commit f8cd291344)

Change-Id: I4947ba4578b5a41a30e487f5572412cb6ed79a1b
Signed-off-by: Marc Jones <marcj303@gmail.com>
Reviewed-on: https://review.coreboot.org/c/coreboot/+/55768
Reviewed-by: Martin Roth <martinroth@google.com>
Reviewed-by: Jay Talbott <JayTalbott@sysproconsulting.com>
Tested-by: build bot (Jenkins) <no-reply@coreboot.org>
2021-06-25 04:11:57 +00:00
Elyes HAOUAS
4b776b705f drivers/ipmi/ipmi_fru: Add missing <stdlib.h>
malloc() needs <stdlib.h>

Original-Change-Id: I0cf6a5b76543cb6dac584de6628cfc459d5a60a8
Original-Signed-off-by: Elyes HAOUAS <ehaouas@noos.fr>
Original-Reviewed-on: https://review.coreboot.org/c/coreboot/+/37884
Original-Reviewed-by: Kyösti Mälkki <kyosti.malkki@gmail.com>
Original-Tested-by: build bot (Jenkins) <no-reply@coreboot.org>
(cherry picked from commit f07d7dc2fd)

Change-Id: I7febb9695199896e3f918b331e0b073d664883e9
Signed-off-by: Marc Jones <marcj303@gmail.com>
Reviewed-on: https://review.coreboot.org/c/coreboot/+/55767
Tested-by: build bot (Jenkins) <no-reply@coreboot.org>
Reviewed-by: Martin Roth <martinroth@google.com>
Reviewed-by: Jay Talbott <JayTalbott@sysproconsulting.com>
2021-06-25 04:11:13 +00:00
Eugene Myers
30bc0a4b66 arch/x86/include/arch: Add SMM_TASK_STATE_SEG
This define is used to set up the STM SMM Descriptor table tr entry.

Original-Signed-off-by: Eugene D. Myers <edmyers@tycho.nsa.gov>
Original-Change-Id: Iddb1f45444d03465a66a4ebb9fde5f206dc5b300
Original-Reviewed-on: https://review.coreboot.org/c/coreboot/+/38657
Original-Tested-by: build bot (Jenkins) <no-reply@coreboot.org>
Original-Reviewed-by: ron minnich <rminnich@gmail.com>

Change-Id: I13a237c1372b79756e19d7ecbbd1946a44f2049f
Signed-off-by: Eugene Myers <edmyers@tycho.nsa.gov>
Reviewed-on: https://review.coreboot.org/c/coreboot/+/55620
Tested-by: build bot (Jenkins) <no-reply@coreboot.org>
Reviewed-by: Patrick Georgi <pgeorgi@google.com>
2021-06-23 08:38:51 +00:00
Marc Jones
44b614aef5 mainboard/ocp/monolake: Fix up Kconfig to match devicetree.cb
Remove the Gbe option and enable EHCI1 to match devicetree.cb.

Change-Id: I122175aec313da0800f94da8b2cdf20cc498824f
Signed-off-by: Marc Jones <marcjones@sysproconsulting.com>
Reviewed-on: https://review.coreboot.org/c/coreboot/+/54882
Reviewed-by: Stefan Reinauer <stefan.reinauer@coreboot.org>
Reviewed-by: Angel Pons <th3fanbus@gmail.com>
Tested-by: build bot (Jenkins) <no-reply@coreboot.org>
2021-06-16 05:10:11 +00:00
Marc Jones
1d3fbda9ee src/drivers/ipmi: Add DEBUG_IPMI option
IPMI debug was extra spewy, so add a debug option as SPI and
other drivers have when they need to be debugged.

Original-Signed-off-by: Marc Jones <marcjones@sysproconsulting.com>
Original-Reviewed-on: https://review.coreboot.org/c/coreboot/+/52449
Original-Tested-by: build bot (Jenkins) <no-reply@coreboot.org>
Original-Reviewed-by: Angel Pons <th3fanbus@gmail.com>
(cherry picked from commit dc12daf277)

Change-Id: If586b5feea74de0e6ed677af18e61dedf1216939
Signed-off-by: Marc Jones <marcjones@sysproconsulting.com>
Reviewed-on: https://review.coreboot.org/c/coreboot/+/54878
Tested-by: build bot (Jenkins) <no-reply@coreboot.org>
Reviewed-by: Stefan Reinauer <stefan.reinauer@coreboot.org>
2021-06-16 04:21:06 +00:00
Werner Zeh
3ec21b07fb .gitmodules: Update intel-microcode submodule to track branch=main
The 3rdparty submodule 'intel-microcode' has changed the branch from
'master' to 'main'. As we do not set any specific branch name in our
config, it defaults to 'master' which makes
"git submodule update --remote --rebase 3rdparty/intel-microcode"
to fail.

This patch adds the branch name in .gitmodules to match the upstream
name.

Change-Id: I7b6d7921a21af4eb3bcc7ce4e5a8ea21c38c89a3
Signed-off-by: Werner Zeh <werner.zeh@siemens.com>
Reviewed-on: https://review.coreboot.org/c/coreboot/+/55305
Tested-by: build bot (Jenkins) <no-reply@coreboot.org>
Reviewed-by: Mario Scheithauer <mario.scheithauer@siemens.com>
Reviewed-by: Marc Jones <marc@marcjonesconsulting.com>
2021-06-10 05:39:18 +00:00
Marc Jones
463aee755e mainboard/ocp/monolake: Clean up devicetree.cb
Clean up the device tree as noted by the coreboot log.
 PCI: Leftover static devices:
 PCI: 00:02.2
 PCI: 00:02.3
 PCI: 00:19.0
 PCI: 00:1d.0
 PCI: 00:1f.5
 PCI: Check your devicetree.cb.

 PCI: 00:02.2 - Keep - "off" setting disables the root port
 PCI: 00:02.3 - Remove - there is no 2.3 root port
 PCI: 00:19.0 - Remove - Gigabit controller is disabled on Mono Lake
 PCI: 00:1d.0 - Keep - EHCI enable patch to follow
 PCI: 00:1f.5 - Remove - Second SATA device not enabled

Change-Id: I200acdda07f6bd6a060de3c4b4d335d9227216ed
Signed-off-by: Marc Jones <marcjones@sysproconsulting.com>
Reviewed-on: https://review.coreboot.org/c/coreboot/+/54881
Tested-by: build bot (Jenkins) <no-reply@coreboot.org>
Reviewed-by: Stefan Reinauer <stefan.reinauer@coreboot.org>
2021-06-09 04:09:14 +00:00
Marc Jones
4a3e7dd31d src/mainboard/ocp/monolake: Set end of post GPIO
Set the end of post GPIO to the BMC. This gets IPMI working on the BMC.

Change-Id: I1a0055cdfd4a973b5f42570723bd95f1844dd9a7
Signed-off-by: Marc Jones <marcjones@sysproconsulting.com>
Reviewed-on: https://review.coreboot.org/c/coreboot/+/54880
Tested-by: build bot (Jenkins) <no-reply@coreboot.org>
Reviewed-by: Stefan Reinauer <stefan.reinauer@coreboot.org>
2021-05-27 14:43:26 +00:00
Marc Jones
bf2f0757a7 src/soc/intel/fsp_boradwell_de: Update ACPI FADT GPE entries
Update the FADT for fwts errors for the GPE entries.
Fix GPE0 access size and remove GPE1 address space ID.

Change-Id: Iea43b534fa119d17cb2bafef8f72d73bcba3a650
Signed-off-by: Marc Jones <marcjones@sysproconsulting.com>
Reviewed-on: https://review.coreboot.org/c/coreboot/+/54879
Tested-by: build bot (Jenkins) <no-reply@coreboot.org>
Reviewed-by: Stefan Reinauer <stefan.reinauer@coreboot.org>
2021-05-27 14:41:49 +00:00
Jonathan Zhang
da2827949e mb/facebook/watson/v2: Reserve memory region for CPLD access
For watson_v2 variant, add lpc_lgmr register in device tree
configuration to access CPLD regsiters.

TESTED=booted watson_v2 server into target OS, confirm
CPLD register access:
devmem2 0xB0000100
Value at address 0xb0000100: 0x00020003

Signed-off-by: Jonathan Zhang <jonzhang@fb.com>
Signed-off-by: Ravi Rama <rrama@arista.com>
Change-Id: I43ee89b8609c64bccf5a21171d8ff192e6aca0ef
Reviewed-on: https://review.coreboot.org/c/coreboot/+/51718
Reviewed-by: Angel Pons <th3fanbus@gmail.com>
Tested-by: build bot (Jenkins) <no-reply@coreboot.org>
2021-03-28 16:07:53 +00:00
Jonathan Zhang
9f53477768 soc/intel/fsp_broadwell_de: Set up LPC Generic Memory Range register
If mainboard devicetree config defines lpc_lgmr, use it to
set up LPC Generic Memory Range register. Also set up
64KiB memory resource.

Signed-off-by: Jonathan Zhang <jonzhang@fb.com>
Change-Id: Iec94f7364c332789f75c2562e910ea5db4ffad23
Reviewed-on: https://review.coreboot.org/c/coreboot/+/51717
Reviewed-by: Angel Pons <th3fanbus@gmail.com>
Tested-by: build bot (Jenkins) <no-reply@coreboot.org>
2021-03-28 16:07:17 +00:00
Jonathan Zhang
8b22c55855 soc/intel/fsp_broadwell_de: Add definition for LGMR
Add definition for LPC Generic Memory Range register.

Signed-off-by: Jonathan Zhang <jonzhang@fb.com>
Change-Id: I7c76bacdf692e72849547106f29b614345f505c1
Reviewed-on: https://review.coreboot.org/c/coreboot/+/51716
Reviewed-by: Angel Pons <th3fanbus@gmail.com>
Tested-by: build bot (Jenkins) <no-reply@coreboot.org>
2021-03-24 07:53:52 +00:00
Jonathan Zhang
570ae23516 mb/facebook/watson/v2: enable IPMI to be detected as PNP device
Watson v2 mainboard has hardware support and OpenBMC support for IPMI.

Add drivers/ipmi to the device tree of watson v2 mainboard.

Use original device tree for watson mainboard.

TESTED=booted watson v2 board, and tested ipmitool command:
   0 | OEM record fb | 2800000000f0ffffffffffffff

Signed-off-by: Ravi Rama <rrama@arista.com>
Signed-off-by: Jonathan Zhang <jonzhang@fb.com>
Change-Id: I1be653278dbfd704d24756cf82be73bdae4bb13c
Reviewed-on: https://review.coreboot.org/c/coreboot/+/51311
Reviewed-by: Angel Pons <th3fanbus@gmail.com>
Reviewed-by: Christian Walter <christian.walter@9elements.com>
Tested-by: build bot (Jenkins) <no-reply@coreboot.org>
2021-03-10 19:25:25 +00:00
Jonathan Zhang
019c0049a2 mb/fb/watson: enable IPMI_KCS for watson_v2
For watson_v2 mainboard variant:
* Enable IPMI_KCS in config.
* In early_mainboard_romstage_entry(), enable LPC IO ports
for IPMI over KCS.

Signed-off-by: Ravi Rama <rrama@arista.com>
Signed-off-by: Jonathan Zhang <jonzhang@fb.com>
Change-Id: Ie0e718b44889678c49f3d61cccd0e33b306fc6f3
Reviewed-on: https://review.coreboot.org/c/coreboot/+/51310
Reviewed-by: Angel Pons <th3fanbus@gmail.com>
Reviewed-by: Christian Walter <christian.walter@9elements.com>
Tested-by: build bot (Jenkins) <no-reply@coreboot.org>
2021-03-10 19:25:05 +00:00
Jonathan Zhang
2f32b5b5d0 soc/intel/fsp_broadwell_de: add PCH_DEV_LPC definition
Signed-off-by: Jonathan Zhang <jonzhang@fb.com>
Change-Id: I2292bf1f6b5d17f95f8e8e41c6d9f07781f22576
Reviewed-on: https://review.coreboot.org/c/coreboot/+/51309
Reviewed-by: Angel Pons <th3fanbus@gmail.com>
Reviewed-by: Christian Walter <christian.walter@9elements.com>
Tested-by: build bot (Jenkins) <no-reply@coreboot.org>
2021-03-10 19:24:51 +00:00
Jonathan Zhang
8916d12426 mb/facebook/watson: include variant subdirectory
watson_v2 mainboard variant has its own code to be built in. Update
Makefile.inc of mainboard directory to include variant subdirectory.

Signed-off-by: Jonathan Zhang <jonzhang@fb.com>
Change-Id: I21ee1c575b3b6e4278955c12d6e4f7109eb75105
Reviewed-on: https://review.coreboot.org/c/coreboot/+/51308
Reviewed-by: Angel Pons <th3fanbus@gmail.com>
Reviewed-by: Christian Walter <christian.walter@9elements.com>
Tested-by: build bot (Jenkins) <no-reply@coreboot.org>
2021-03-10 19:24:34 +00:00
Marc Jones
236ca58a76 3rdparty/intel-microcode: Update to 2020118 release
Update the 4.11_branch to the 2020118 intel microcde release,
which is the current main HEAD.

Change-Id: Ic010594a59b692b18eb40656c283c080c34c4d2c
Signed-off-by: Marc Jones <marcjones@sysproconsulting.com>
Reviewed-on: https://review.coreboot.org/c/coreboot/+/50553
Reviewed-by: Jay Talbott <JayTalbott@sysproconsulting.com>
Reviewed-by: Patrick Georgi <pgeorgi@google.com>
Tested-by: build bot (Jenkins) <no-reply@coreboot.org>
2021-02-22 07:35:05 +00:00
Marc Jones
413027b0c7 mainboard/ocp/monolake: Remove ACPI PNP0C0C device
Remove the empty PWRB ACPI device. The power button is controlled by
the fixed power button model in PM1x_EVT_BLK and doesn't have a
control method. The only device in mainboard.asl was PWRB, so remove
the file.

This fixes the FWTS error:
acpi_pwrb: PWR_Button field in FACP should not be zero with ACPI PNP0C0C device.

Change-Id: Idd8c3588694b913b52ca6509332603e3525117b7
Signed-off-by: Marc Jones <marcjones@sysproconsulting.com>
Reviewed-on: https://review.coreboot.org/c/coreboot/+/50569
Tested-by: build bot (Jenkins) <no-reply@coreboot.org>
Reviewed-by: Jay Talbott <JayTalbott@sysproconsulting.com>
Reviewed-by: Paul Menzel <paulepanter@users.sourceforge.net>
Reviewed-by: Angel Pons <th3fanbus@gmail.com>
2021-02-22 07:34:38 +00:00
Marc Jones
6f1a75950a soc/intel/fsp_broadwell_de: Use smm_module_loaderv2
Use smm_module_loaderv2 to support 16core/32thread Broadwell_DE.
Tested SMM handler loads on all 32 threads.

Change-Id: I3a6e17e8590a2af9b4e7c701f8fccfccfa3ea94b
Signed-off-by: Marc Jones <marcjones@sysproconsulting.com>
Reviewed-on: https://review.coreboot.org/c/coreboot/+/50314
Tested-by: build bot (Jenkins) <no-reply@coreboot.org>
Reviewed-by: Stefan Reinauer <stefan.reinauer@coreboot.org>
Reviewed-by: Jay Talbott <JayTalbott@sysproconsulting.com>
2021-02-22 07:34:30 +00:00
Rocky Phagura
5434988bac cpu/x86/smm: Introduce SMM module loader version 2
Xeon-SP 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 specific 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 be 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.
Original-Change-Id: I00a23a5f2a46110536c344254868390dbb71854c
Original-Signed-off-by: Rocky Phagura <rphagura@fb.com>
Original-Reviewed-on: https://review.coreboot.org/c/coreboot/+/43684
Original-Tested-by: build bot (Jenkins) <no-reply@coreboot.org>
Original-Reviewed-by: Angel Pons <th3fanbus@gmail.com>

(cherry picked from commit afb7a81478)
Signed-off-by: Marc Jones <marcjones@sysproconsulting.com>

Change-Id: I76bb506de56c816f6c0635bfd990125b789c5877
Reviewed-on: https://review.coreboot.org/c/coreboot/+/50313
Tested-by: build bot (Jenkins) <no-reply@coreboot.org>
Reviewed-by: Stefan Reinauer <stefan.reinauer@coreboot.org>
Reviewed-by: Jay Talbott <JayTalbott@sysproconsulting.com>
Reviewed-by: Rocky Phagura
2021-02-22 07:34:23 +00:00
Eugene D Myers
6b395cb190 intel/stm: Place resource list right below MSEG
Suggested by Nico Huber in CB:38765.

This placement makes the address calculation simpler and
makes its location indepedent of the number of CPUs.

As part of the change in the BIOS resource list address
calculation, the `size` variable was factored out of the
conditional in line 361, thus eliminating the else.

Original-Change-Id: I9ee2747474df02b0306530048bdec75e95413b5d
Original-Signed-off-by: Eugene D Myers <cedarhouse@comcast.net>
Original-Reviewed-on: https://review.coreboot.org/c/coreboot/+/40437
Original-Reviewed-by: Nico Huber <nico.h@gmx.de>
Original-Reviewed-by: Angel Pons <th3fanbus@gmail.com>
Original-Tested-by: build bot (Jenkins) <no-reply@coreboot.org>

(cherry picked from commit 076605bc92)
Signed-off-by: Marc Jones <marcjones@sysproconsulting.com>

Change-Id: Ie62e2bdccd2d09084cc39a0f2fe32df236c08cd6
Reviewed-on: https://review.coreboot.org/c/coreboot/+/50312
Tested-by: build bot (Jenkins) <no-reply@coreboot.org>
Reviewed-by: Stefan Reinauer <stefan.reinauer@coreboot.org>
Reviewed-by: Jay Talbott <JayTalbott@sysproconsulting.com>
Reviewed-by: Eugene Myers <cedarhouse1@comcast.net>
Reviewed-by: Paul Menzel <paulepanter@users.sourceforge.net>
2021-02-22 07:34:16 +00:00
Nico Huber
b450c8d2cb cpu/x86/smm: Add overflow check
Rather bail out than run into undefined behavior.

Original-Change-Id: Ife26a0abed0ce6bcafe1e7cd8f499618631c4df4
Original-Signed-off-by: Nico Huber <nico.h@gmx.de>
Original-Reviewed-on: https://review.coreboot.org/c/coreboot/+/38763
Original-Tested-by: build bot (Jenkins) <no-reply@coreboot.org>
Original-Reviewed-by: Patrick Rudolph <siro@das-labor.org>
Original-Reviewed-by: Angel Pons <th3fanbus@gmail.com>
Original-Reviewed-by: <cedarhouse1@comcast.net>

(cherry picked from commit 6d5f007813)
Signed-off-by: Marc Jones <marcjones@sysproconsulting.com>

Change-Id: I28e10d8836ab80c6fec9d3414c795c5e6ff312e8
Reviewed-on: https://review.coreboot.org/c/coreboot/+/50311
Tested-by: build bot (Jenkins) <no-reply@coreboot.org>
Reviewed-by: Stefan Reinauer <stefan.reinauer@coreboot.org>
Reviewed-by: Jay Talbott <JayTalbott@sysproconsulting.com>
2021-02-22 07:34:08 +00:00
Arthur Heymans
fc8a6fa93a cpu/x86/smm: Add smm_size to relocatable smmstub
To mitigate against sinkhole in software which is required on
pre-sandybridge hardware, the smm entry point needs to check if the
LAPIC base is between smbase and smbase + smmsize. The size needs to
be available early so add them to the relocatable module parameters.

When the smmstub is used to relocate SMM the default SMM size 0x10000
is provided. On the permanent handler the size provided by
get_smm_info() is used.

Original-Change-Id: I0df6e51bcba284350f1c849ef3d012860757544b
Original-Signed-off-by: Arthur Heymans <arthur@aheymans.xyz>
Original-Reviewed-on: https://review.coreboot.org/c/coreboot/+/37288
Original-Tested-by: build bot (Jenkins) <no-reply@coreboot.org>
Original-Reviewed-by: Patrick Georgi <pgeorgi@google.com>

(cherry picked from commit a3eb3df01c)
Signed-off-by: Marc Jones <marcjones@sysproconsulting.com>

Change-Id: I4948639a513b196382eb38616fe872b72bb7e59e
Reviewed-on: https://review.coreboot.org/c/coreboot/+/50310
Tested-by: build bot (Jenkins) <no-reply@coreboot.org>
Reviewed-by: Stefan Reinauer <stefan.reinauer@coreboot.org>
Reviewed-by: Jay Talbott <JayTalbott@sysproconsulting.com>
2021-02-22 07:34:03 +00:00
Eugene Myers
c7af5ef509 security/intel/stm: Check for processor STM support
Check to ensure that dual monitor mode is supported on the
current processor. Dual monitor mode is normally supported on
any Intel x86 processor that has VTx support.  The STM is
a hypervisor that executes in SMM dual monitor mode.  This
check should fail only in the rare case were dual monitor mode
is disabled.  If the check fails, then the STM will not
be initialized by coreboot.

Original-Signed-off-by: Eugene D. Myers <edmyers@tycho.nsa.gov>
Original-Change-Id: I518bb2aa1bdec94b5b6d5e991d7575257f3dc6e9
Original-Reviewed-on: https://review.coreboot.org/c/coreboot/+/38836
Original-Tested-by: build bot (Jenkins) <no-reply@coreboot.org>
Original-Reviewed-by: Nico Huber <nico.h@gmx.de>

(cherry picked from commit 5544f62746)
Signed-off-by: Marc Jones <marcjones@sysproconsulting.com>

Change-Id: I312570ca28329490006283251f69dd83ef64af40
Reviewed-on: https://review.coreboot.org/c/coreboot/+/50309
Tested-by: build bot (Jenkins) <no-reply@coreboot.org>
Reviewed-by: Stefan Reinauer <stefan.reinauer@coreboot.org>
Reviewed-by: Jay Talbott <JayTalbott@sysproconsulting.com>
2021-02-22 07:33:53 +00:00
Eugene Myers
bff4cb0558 security/intel/stm: Add STM support
This update is a combination of all four of the patches so that the
commit can be done without breaking parts of coreboot.  This possible
breakage is because of the cross-dependencies between the original
separate patches would cause failure because of data structure changes.

security/intel/stm

This directory contains the functions that check and move the STM to the
MSEG, create its page tables, and create the BIOS resource list.

The STM page tables is a six page region located in the MSEG and are
pointed to by the CR3 Offset field in the MSEG header.  The initial
page tables will identity map all memory between 0-4G.  The STM starts
in IA32e mode, which requires page tables to exist at startup.

The BIOS resource list defines the resources that the SMI Handler is
allowed to access.  This includes the SMM memory area where the SMI
handler resides and other resources such as I/O devices.  The STM uses
the BIOS resource list to restrict the SMI handler's accesses.

The BIOS resource list is currently located in the same area as the
SMI handler.  This location is shown in the comment section before
smm_load_module in smm_module_loader.c

Note: The files within security/intel/stm come directly from their
Tianocore counterparts.  Unnecessary code has been removed and the
remaining code has been converted to meet coreboot coding requirements.

For more information see:
     SMI Transfer Monitor (STM) User Guide, Intel Corp.,
     August 2015, Rev 1.0, can be found at firmware.intel.com

include/cpu/x86:

Addtions to include/cpu/x86 for STM support.

cpu/x86:

STM Set up - The STM needs to be loaded into the MSEG during BIOS
initialization and the SMM Monitor Control MSR be set to indicate
that an STM is in the system.

cpu/x86/smm:

SMI module loader modifications needed to set up the
SMM descriptors used by the STM during its initialization

Original-Change-Id: If4adcd92c341162630ce1ec357ffcf8a135785ec
Original-Signed-off-by: Eugene D. Myers <edmyers@tycho.nsa.gov>
Original-Reviewed-on: https://review.coreboot.org/c/coreboot/+/33234
Original-Tested-by: build bot (Jenkins) <no-reply@coreboot.org>
Original-Reviewed-by: Patrick Georgi <pgeorgi@google.com>
Original-Reviewed-by: ron minnich <rminnich@gmail.com>

(cherry picked from commit ae438be578)
Signed-off-by: Marc Jones <marcjones@sysproconsulting.com>

Change-Id: Ic0131fcada9f43c9817c8a0a942d0419c7023130
Reviewed-on: https://review.coreboot.org/c/coreboot/+/50308
Tested-by: build bot (Jenkins) <no-reply@coreboot.org>
Reviewed-by: Stefan Reinauer <stefan.reinauer@coreboot.org>
2021-02-22 07:33:43 +00:00
Deomid "rojer" Ryabkov
2085d6f46a Apply locked MSR check to all BDW-DE platforms
It was initially applied to Wedge100 and MonoLake in CB:30290
and the issue has now been observed on Watson as well.

Original change: [CB:30290][commit 817994c1be]

Signed-off-by: Deomid "rojer" Ryabkov <rojer9@fb.com>
Change-Id: Ica9557ff159321abed55f9402aee626f18fe526b
Reviewed-on: https://review.coreboot.org/c/coreboot/+/50307
Reviewed-by: Angel Pons <th3fanbus@gmail.com>
Tested-by: build bot (Jenkins) <no-reply@coreboot.org>
2021-02-07 21:55:09 +00:00
Philipp Deppenwiese
1474ddb722 security/tpm: Add crypto agility support
* Added tlcl_extend size checks
* Added TPM2 tlcl_extend crypto agility

TESTED=On Facebook Watson_V2 mainboard, the TCPA log now shows correct hash content and algorithm:

PCR-0 62571891215b4efc1ceab744ce59dd0b66ea6f73 SHA1 [VBOOT: boot mode]
instead of:
PCR-0 62571891215b4efc1ceab744ce59dd0b66ea6f73 SHA256 [VBOOT: boot mode]

Change-Id: I9cc8d994081896e8c0d511c31e9741297227afef
Signed-off-by: Philipp Deppenwiese <zaolin@das-labor.org>
Reviewed-on: https://review.coreboot.org/c/coreboot/+/48742
Tested-by: build bot (Jenkins) <no-reply@coreboot.org>
Reviewed-by: Angel Pons <th3fanbus@gmail.com>
2021-02-07 21:52:43 +00:00
Arthur Heymans
1c7b526de1 sec/intel/txt/Kconfig: Remove the menu for including ACMs
This is consistent with how other binaries (e.g. FSP) are added via
Kconfig. This also makes it more visible that things need to be
configured.

Change-Id: I399de6270cc4c0ab3b8c8a9543aec0d68d3cfc03
Signed-off-by: Arthur Heymans <arthur@aheymans.xyz>
Reviewed-on: https://review.coreboot.org/c/coreboot/+/45003
Tested-by: build bot (Jenkins) <no-reply@coreboot.org>
2020-11-08 17:20:42 +00:00
Marc Jones
76b81ff4c7 ocp/monolake: Simplify mainboard dsdt.asl
Include the soc uncore.asl for the uncore irq routing. Generates
the same asl.

Change-Id: I2062520a06626f86fb0d78e8b23533f987b37ca0
Signed-off-by: Marc Jones <marcjones@sysproconsulting.com>
Reviewed-on: https://review.coreboot.org/c/coreboot/+/46985
Tested-by: build bot (Jenkins) <no-reply@coreboot.org>
Reviewed-by: Jay Talbott <JayTalbott@sysproconsulting.com>
Reviewed-by: Stefan Reinauer <stefan.reinauer@coreboot.org>
2020-10-30 17:11:43 +00:00
Mario Scheithauer
a695655915 mb/siemens/mc_bdx1: Fix IASL warning reported as error
Latest IASL version (20200717) leads to a build error on 4.11_branch.

dsdt.asl 1121: Device (UNC0)
Warning 3073 - Multiple types (Device object requires either a _HID or
_ADR, but not both)

This warning reported as error was ignored in older IASL versions.
The address object (_ADR) is not needed because a valid hardware ID
(_HID) for the device is available.

Change-Id: Iae5c91739ed9caea2dbb5996e2f093ed6fc47e93
Signed-off-by: Mario Scheithauer <mario.scheithauer@siemens.com>
Reviewed-on: https://review.coreboot.org/c/coreboot/+/46129
Tested-by: build bot (Jenkins) <no-reply@coreboot.org>
Reviewed-by: HAOUAS Elyes <ehaouas@noos.fr>
Reviewed-by: Stefan Reinauer <stefan.reinauer@coreboot.org>
Reviewed-by: Angel Pons <th3fanbus@gmail.com>
Reviewed-by: Christian Walter <christian.walter@9elements.com>
2020-10-12 06:25:00 +00:00
Jonathan Zhang
6a7531431d mb/facebook/watson: increase size of RO_VPD and RW_VPD
The current size of RO_VPD (and RW_VPD) is too small. We have case that
adding VPD parameters silently corrupts the coreboot region next to
RO_VPD.

Increase the size of both RO_VPD and RW_VPD to 0x4000 bytes.

TESTED=build coreboot image for watson, add large size VPD parameter to
the image, boot watson server into target OS.

Signed-off-by: Jonathan Zhang <jonzhang@fb.com>
Change-Id: I428b7de6462b47492d9526042018395d2f99cb2a
Reviewed-on: https://review.coreboot.org/c/coreboot/+/44531
Tested-by: build bot (Jenkins) <no-reply@coreboot.org>
Reviewed-by: Angel Pons <th3fanbus@gmail.com>
Reviewed-by: Paul Menzel <paulepanter@users.sourceforge.net>
2020-08-24 09:17:25 +00:00
Jonathan Zhang
aae448601c soc/intel/fsp_broadwell_de: examine ACM status at romstage entry
When INTEL_TXT is set, at romstage entry check if startup ACM worked correctly
by probing TXT_ERROR register.

Signed-off-by: Philipp Deppenwiese <zaolin.daisuki@gmail.com>
Signed-off-by: Jonathan Zhang <jonzhang@fb.com>
Change-Id: I6f423df8b05dc44220a9bad3674f687bac94e335
Reviewed-on: https://review.coreboot.org/c/coreboot/+/42713
Reviewed-by: Angel Pons <th3fanbus@gmail.com>
Tested-by: build bot (Jenkins) <no-reply@coreboot.org>
2020-08-10 00:26:49 +00:00
Philipp Deppenwiese
ea7fde7070 security/intel/txt: Add Intel TXT support
Add TXT ramstage driver:
 * Show startup errors
 * Check for TXT reset
 * Check for Secrets-in-memory
 * Add assembly for GETSEC instruction
 * Check platform state if GETSEC instruction is supported
 * Configure TXT memory regions
 * Lock TXT
 * Protect TSEG using DMA protected regions
 * Place SINIT ACM
 * Print information about ACMs

Extend the `security_clear_dram_request()` function:
 * Clear all DRAM if secrets are in memory

Add a config so that the code gets build-tested. Since BIOS and SINIT
ACM binaries are not available, use the STM binary as a placeholder.

Tested on OCP Wedge100s and Facebook Watson
 * Able to enter a Measured Launch Environment using SINIT ACM and TBOOT
 * Secrets in Memory bit is set on ungraceful shutdown
 * Memory is cleared after ungraceful shutdown

Change-Id: Iaf4be7f016cc12d3971e1e1fe171e6665e44c284
Signed-off-by: Philipp Deppenwiese <zaolin@das-labor.org>
Reviewed-on: https://review.coreboot.org/c/coreboot/+/37016
Tested-by: build bot (Jenkins) <no-reply@coreboot.org>
Reviewed-by: Christian Walter <christian.walter@9elements.com>
(cherry picked from commit 5f9f77672d)
Reviewed-on: https://review.coreboot.org/c/coreboot/+/42712
Reviewed-by: Angel Pons <th3fanbus@gmail.com>
Reviewed-by: Jonathan Zhang <jonzhang@fb.com>
2020-08-10 00:26:35 +00:00
Nico Huber
b43431d58e mb/lenovo/t60: Fix override devicetrees
Commit c1dc2d5e68 (mb/lenovo/t60: Switch to override tree) converted
these boards to override trees, but some device nodes were missed.
Said nodes are essential, as `chip` configuration data is always tied
to device nodes. The resulting `static.c` contained multiple copies
of the `chip` configuration structs, but the wrong ones were hooked up.

The therefore missing configuration of the clockgen led to general
instability, especially with SMP under Linux (probably due to the
attempt to enter lower C states on an idle core). Passing `maxcpus=1`
to the Linux kernel served as a workaround.

Change-Id: I6c26d633d1860cf9a5415994444e75ae1c2e59ad
Signed-off-by: Nico Huber <nico.h@gmx.de>
Reviewed-on: https://review.coreboot.org/c/coreboot/+/43065
Reviewed-by: Arthur Heymans <arthur@aheymans.xyz>
Tested-by: build bot (Jenkins) <no-reply@coreboot.org>
2020-08-04 12:25:41 +00:00
Morgan Jang
fabe8f5a95 mb/ocp/monolake: Create SMBIOS type 16 for Monolake platform
TEST=Use "dmidecode -t 16" in Linux to check if SMBIOS type 16 exists

Change-Id: Ie057742112f14447b226d432417d9301d4aea958
Signed-off-by: Morgan Jang <Morgan_Jang@wiwynn.com>
Reviewed-on: https://review.coreboot.org/c/coreboot/+/37233
Reviewed-by: Angel Pons <th3fanbus@gmail.com>
Tested-by: build bot (Jenkins) <no-reply@coreboot.org>
2020-07-24 09:46:27 +00:00
Jonathan Zhang
380c4b447c mb/facebook/watson: select VPD_SMBIOS_VERSION
Select VPD, GENERATE_SMBIOS_TABLES, VPD_SMBIOS_VERSION so that
"firmware_version" key value in RO_VPD is reported in smbios type
0 as BIOS version.

TEST=Build coreboot image for WatsonV2, run "vpd -s
firmware_version=FB_OSF_1.2 -i RO_VPD -f build/coreboot.rom"
command to add firmware_version key value pair in RO_VPD,
flash the image to WatsonV2 and reboot it, run dmidecode to verify:

[root@localhost ~]# dmidecode -t 0
...
BIOS Information
	Vendor: coreboot
	Version: FB_OSF_1.2
...

Signed-off-by: Jonathan Zhang <jonzhang@fb.com>
Change-Id: I31fb2cef01161175a0c01094c5445f7fa340f2d0
Reviewed-on: https://review.coreboot.org/c/coreboot/+/42942
Tested-by: build bot (Jenkins) <no-reply@coreboot.org>
Reviewed-by: Philipp Deppenwiese <zaolin.daisuki@gmail.com>
Reviewed-by: insomniac <insomniac@slackware.it>
Reviewed-by: Christian Walter <christian.walter@9elements.com>
2020-07-07 17:29:19 +00:00
Johnny Lin
c0736c5a55 smbios: Add option VPD_SMBIOS_VERSION that reads BIOS version from a VPD variable
If VPD_SMBIOS_VERSION is selected, it would read VPD_RO variable that can
override SMBIOS type 0 version.

One special scenario of using this feature is to assign a BIOS version to
a coreboot image without the need to rebuild from source.
VPD_SMBIOS_VERSION default is n.

Tested=On OCP Delta Lake, dmidecode -t 0 can see the version being updated
from VPD.

Change-Id: Iee62ed900095001ffac225fc629b3f2f52045e30
Signed-off-by: Johnny Lin <johnny_lin@wiwynn.com>
Reviewed-on: https://review.coreboot.org/c/coreboot/+/42029
Tested-by: build bot (Jenkins) <no-reply@coreboot.org>
Reviewed-by: insomniac <insomniac@slackware.it>
Reviewed-by: Julius Werner <jwerner@chromium.org>
(cherry picked from commit c746a748c4)
Reviewed-on: https://review.coreboot.org/c/coreboot/+/42747
Reviewed-by: Philipp Deppenwiese <zaolin.daisuki@gmail.com>
2020-07-04 11:21:01 +00:00
Andrey Petrov
df7e1f9a43 soc/intel/fsp_broadwell_de: Check if memory is 'locked'
Under certain conditions TXT can "lock" memory controller for security
purpose. This manifests itself in IMC's SMbus controller failing all SPD
data read requests.  FSP does not detect error condition and fails boot
with "No memory found" issue.

TEST=tested on OCP monolake in 'locked' state

Change-Id: If4637e4293421794a89037ff107e87794c40114a
Signed-off-by: Andrey Petrov <anpetrov@fb.com>
Reviewed-on: https://review.coreboot.org/c/coreboot/+/42710
Tested-by: build bot (Jenkins) <no-reply@coreboot.org>
Reviewed-by: Patrick Rudolph <siro@das-labor.org>
Reviewed-by: Christian Walter <christian.walter@9elements.com>
2020-06-24 11:53:44 +00:00
Jonathan Zhang
674a825cd7 mb/fb/watson/watson_v2: configure PCI bifurcation
Watson V2 server has different PCIe bifurcation configuration, comparing to
Watson server.

Add a watson_v2 variant directory. Allow variant to customize UPD parameters.

Configure UPD parameters to define PCIe bifurcation configuration for Watson
V2 server.

Signed-off-by: Jonathan Zhang <jonzhang@fb.com>
Change-Id: I3b57c64dea6f3a468336fcdb1e948dfcd897e60c
Reviewed-on: https://review.coreboot.org/c/coreboot/+/41433
Tested-by: build bot (Jenkins) <no-reply@coreboot.org>
Reviewed-by: Philipp Deppenwiese <zaolin.daisuki@gmail.com>
2020-05-25 10:21:52 +00:00
Jonathan Zhang
631eac99ed mb/facebook/watson: add variant watson_v2
Watson V2 is the 2nd board variant of Watson.

One aspect of the difference between watson V2 and watson (V1) is:
* Watson V2 has TPM2 chip instead of TPM1 chip.
* Watson V2 needs to have measured boot enabled.

TESTED=Made Watson V2 image, checked boot log and verfied that TPM2
is detected by both coreboot and target OS, that coreboot is measured.

TPM: Measured FMAP: COREBOOT CBFS: bootblock into PCR 2
TPM: Measured FMAP: COREBOOT CBFS: fallback/romstage into PCR 2
TPM: Measured FMAP: COREBOOT CBFS: fallback/ramstage into PCR 2
TPM: Measured FMAP: COREBOOT CBFS: cpu_microcode_blob.bin into PCR 2
TPM: Measured FMAP: COREBOOT CBFS: fallback/dsdt.aml into PCR 2
TPM: Measured FMAP: COREBOOT CBFS: fallback/payload into PCR 2

Signed-off-by: Jonathan Zhang <jonzhang@fb.com>
Change-Id: Iabf4183dfeabb2f9946dbb5c98c60b7c0cdba711
Reviewed-on: https://review.coreboot.org/c/coreboot/+/40575
Tested-by: build bot (Jenkins) <no-reply@coreboot.org>
Reviewed-by: David Hendricks <david.hendricks@gmail.com>
2020-04-29 20:24:42 +00:00
Jonathan Zhang
ff6db825c3 mb/facebook/watson: Make watson as a variant
Facebook Watson (V1) board is the first variant of Watson mainboard.

Signed-off-by: Jonathan Zhang <jonzhang@fb.com>
Change-Id: I1164ee9f8d07cebf8d505ca1e164823c1cb5625c
Reviewed-on: https://review.coreboot.org/c/coreboot/+/40541
Tested-by: build bot (Jenkins) <no-reply@coreboot.org>
Reviewed-by: David Hendricks <david.hendricks@gmail.com>
2020-04-29 20:24:09 +00:00
Martin Roth
e33ecb0e08 Makefile.inc: Ignore _HID & _ADR conflicts in Broadwell & Lynxpoint
We haven't been able to update IASL in 8 months because of this
conflict.  Ignoring it doesn't make things any worse than they are now.

Signed-off-by: Martin Roth <martin@coreboot.org>
Change-Id: Iced2e55e9f2aa7a262a5c1ffeff32af78acfa35e
Reviewed-on: https://review.coreboot.org/c/coreboot/+/38810
Tested-by: build bot (Jenkins) <no-reply@coreboot.org>
Reviewed-by: Angel Pons <th3fanbus@gmail.com>
Reviewed-by: HAOUAS Elyes <ehaouas@noos.fr>
Reviewed-by: Nico Huber <nico.h@gmx.de>
Reviewed-by: Paul Menzel <paulepanter@users.sourceforge.net>
(cherry picked from commit 12e9c5ee86)
Reviewed-on: https://review.coreboot.org/c/coreboot/+/38959
Reviewed-by: Patrick Georgi <pgeorgi@google.com>
2020-03-04 15:50:11 +00:00
Nico Huber
98477da405 Makefile.inc: Adapt $(spc) definition
GNU Make 4.3 is more picky about the $(spc) definition. It seems, the
variable ends up empty. The old definition worked for nearly 8 years,
RIP.

Tested with GNU Make 4.2.1 and 4.3.

Change-Id: I7981e0066b550251ae4a98d7b50e83049fc5586a
Signed-off-by: Nico Huber <nico.h@gmx.de>
Reviewed-on: https://review.coreboot.org/c/coreboot/+/38790
Reviewed-by: Angel Pons <th3fanbus@gmail.com>
Reviewed-by: Paul Menzel <paulepanter@users.sourceforge.net>
Tested-by: build bot (Jenkins) <no-reply@coreboot.org>
(cherry picked from commit 0f6f70c394)
Reviewed-on: https://review.coreboot.org/c/coreboot/+/38958
2020-02-19 12:08:24 +00:00
Johnny Lin
93ac30d189 mb/ocp/monolake: Override SMBIOS data with IPMI read FRU data
SMBIOS type 1 data fields are overwritten by FRU product info
area data, SMBIOS type 2 fields are overwritten by FRU
board info area data.

Tested on OCP Mono Lake.

Change-Id: I58cbe95055dea053b115e99f354f40d5902c6a35
Signed-off-by: Johnny Lin <johnny_lin@wiwynn.com>
Reviewed-on: https://review.coreboot.org/c/coreboot/+/37445
Tested-by: build bot (Jenkins) <no-reply@coreboot.org>
Reviewed-by: David Hendricks <david.hendricks@gmail.com>
2019-12-12 15:10:43 +00:00
Johnny Lin
8ac46b937c drivers/ipmi: Add IPMI Read FRU function
Implemented according to IPMI "Platform Management
FRU Information Storage Definition" specification
v1.0 for reading FRU data Product Info Area and
Board Info Area.
SMBIOS data can be updated with the FRU data.

Tested on OCP Mono Lake.

Change-Id: Id6353f5ce3f7ddd3bb161b91364b3cf276d020b8
Signed-off-by: Johnny Lin <johnny_lin@wiwynn.com>
Reviewed-on: https://review.coreboot.org/c/coreboot/+/37444
Tested-by: build bot (Jenkins) <no-reply@coreboot.org>
Reviewed-by: David Hendricks <david.hendricks@gmail.com>
2019-12-12 15:10:32 +00:00
Andrey Petrov
29ce1be9cc mainboard/facebook/watson: Reclaim unused flash space
Currently FMAP does not allocate all the usable space. This change
addresses that by removing unused section and expanding CBFS section.

TEST=tested on actual watson HW

Change-Id: I5f407c11031822d58f11f1a4684845d57653b190
Signed-off-by: Andrey Petrov <anpetrov@fb.com>
Reviewed-on: https://review.coreboot.org/c/coreboot/+/37474
Tested-by: build bot (Jenkins) <no-reply@coreboot.org>
Reviewed-by: Werner Zeh <werner.zeh@siemens.com>
Reviewed-by: Frans Hendriks <fhendriks@eltan.com>
2019-12-05 20:54:26 +00:00
Andrey Petrov
d491ebfe5b [BACKPORT] arch/x86: SMBIOS: Improve core count reporting
Current code uses CPUID leaf 0x1, EBX bits 16:23 to determine number for
"core count". However, it turns out this number has little to do with
real number of cores. According to SDM vol 2A, it stays for "maximum
number of addressable IDs for logical processors in this physical
package". This does not seem to take into account fusing of giving
processor.

The new code determines 'core count' by dividing thread-level cpus by
reported logical cores. This seems to be the only way to arrive
to number of cores as it is reported in official CPU datasheet.

TEST=tested on OCP monolake

Change-Id: Id4ba9e3079f92ffe38f9104ffcfafe62582dd259
Signed-off-by: Andrey Petrov <anpetrov@fb.com>
Reviewed-on: https://review.coreboot.org/c/coreboot/+/36941
Tested-by: build bot (Jenkins) <no-reply@coreboot.org>
Reviewed-by: Werner Zeh <werner.zeh@siemens.com>
(cherry picked from commit 515ef38db4)
Reviewed-on: https://review.coreboot.org/c/coreboot/+/37089
2019-12-05 20:53:53 +00:00
Andrey Petrov
9ad9b3a682 soc/intel/broadwell_de: Re-read SPD on CRC error
I2C bus does not guarantee data integrity. As result, sometimes
we end up detecting CRC errors and not adding DIMMs to SMBIOS tables.
This change adds re-tries on such errors.

TEST=let OCP monolake run without fan and try reading SPD data in tight
loop. CRC errors were reported but subsequent retries were error free.

Change-Id: I650c8cd80f75b603db332024748a91af6171f096
Signed-off-by: Andrey Petrov <anpetrov@fb.com>
Reviewed-on: https://review.coreboot.org/c/coreboot/+/37303
Tested-by: build bot (Jenkins) <no-reply@coreboot.org>
Reviewed-by: Werner Zeh <werner.zeh@siemens.com>
2019-12-05 17:58:23 +00:00
Kyösti Mälkki
e81f20c36a Revert "console,boot_state: Exclude printk() from reported times"
The code in cpu/x86/lapic/apic_timer.c for timer_monotonic_get() is not
SMP safe as LAPIC timers do not run as synchronised as TSCs. So the
reported times with LAPIC_MONOTONIC_TIMER=y at least were incorrect.

Since the approach for this improved times reporting was not completed
wrt. the output format either, revert it from 4.11_branch.

Change-Id: Ie7edae572cf4fee0b9d2497f7690145c2699a809
Signed-off-by: Kyösti Mälkki <kyosti.malkki@gmail.com>
Reviewed-on: https://review.coreboot.org/c/coreboot/+/37396
Tested-by: build bot (Jenkins) <no-reply@coreboot.org>
Reviewed-by: Angel Pons <th3fanbus@gmail.com>
Reviewed-by: Werner Zeh <werner.zeh@siemens.com>
Reviewed-by: Frans Hendriks <fhendriks@eltan.com>
2019-12-03 09:45:36 +00:00
Johnny Lin
c3a8d63788 mb/ocp/monolake: Override SMBIOS UUID with the value sent by BMC
Tested on OCP Mono Lake with dmidecode -t 1 and the expected
UUID is visible.

Change-Id: I0aab4df67b7aaba8be6ddbb13984fffb2b14fe6b
Signed-off-by: Johnny Lin <johnny_lin@wiwynn.com>
Reviewed-on: https://review.coreboot.org/c/coreboot/+/37086
Tested-by: build bot (Jenkins) <no-reply@coreboot.org>
Reviewed-by: David Hendricks <david.hendricks@gmail.com>
2019-11-28 10:51:19 +00:00
Johnny Lin
5566303362 drivers/ipmi: Add IPMI get system GUID support
Tested on OCP Mono Lake.

Change-Id: I541a23341ccce3d45239babb3f0a8a8c8542b226
Signed-off-by: Johnny Lin <johnny_lin@wiwynn.com>
Reviewed-on: https://review.coreboot.org/c/coreboot/+/37085
Reviewed-by: David Hendricks <david.hendricks@gmail.com>
Tested-by: build bot (Jenkins) <no-reply@coreboot.org>
2019-11-28 10:51:08 +00:00
Morgan Jang
9ede3d51e5 src/drivers/ipmi: Implement BMC Get Self Test Result function
According to IPMI SPEC, it is recommended that BIOS includes provisions
for checking and reporting on the basic health of BMC by executing
the Get Self Test Results command and checking the result.

TEST=Check the result in response data to confirm the BMC status is fine
or not.

Change-Id: I20349cec2e8e9420d177d725de2a5560d354fe47
Signed-off-by: Morgan Jang <Morgan_Jang@wiwynn.com>
Reviewed-on: https://review.coreboot.org/c/coreboot/+/36638
Tested-by: build bot (Jenkins) <no-reply@coreboot.org>
Reviewed-by: David Hendricks <david.hendricks@gmail.com>
(cherry picked from commit 5015502414)
Reviewed-on: https://review.coreboot.org/c/coreboot/+/37087
2019-11-27 13:44:50 +00:00
106 changed files with 6327 additions and 494 deletions

5
.gitmodules vendored
View file

@ -34,6 +34,7 @@
url = ../intel-microcode.git
update = none
ignore = dirty
branch = main
[submodule "3rdparty/ffs"]
path = 3rdparty/ffs
url = ../ffs.git
@ -42,3 +43,7 @@
url = ../amd_blobs
update = none
ignore = dirty
[submodule "3rdparty/stm"]
path = 3rdparty/stm
url = ../STM
branch = stmpe

@ -1 +1 @@
Subproject commit 1dd14da6d1ea5cfbd95923653f31c04aac3aa655
Subproject commit 49bb67f32a2e3e631ba1a9a73da1c52e1cac7fd9

View file

@ -99,6 +99,10 @@ The boards in this section are not real mainboards, but emulators.
- [MS-7707](msi/ms7707/ms7707.md)
## OCP
- [Mono Lake](ocp/monolake.md)
## Open Cellular
- [Elgon](opencellular/elgon.md)

View file

@ -0,0 +1,146 @@
# OCP Mono Lake
This page describes coreboot support status for the [OCP] (Open Compute Project)
Mono Lake server platform.
## Introduction
OCP Mono Lake server platform is a component of multi-host server Yosemite-V1.
Facebook [introduced Yosemite] in 2015 and the [Mono Lake was accepted] to OCP in 2019.
Mono Lake server is a single socket BroadwellDE server.
Yosemite-V1 may host up to 4 Mono Lake servers (blades) in one sled.
The Yosemite-V1 system is in mass production. Facebook, Intel, ITRenew and partners
jointly develop Open System Firmware (OSF) solution on Mono Lake as an alternative
solution. The OSF solution is based on coreboot/FSP/LinuxBoot stack. A firmware binary
is available from ITRenew.
coreboot Mono Lake is supported on the coreboot version 4.11 branch.
The Broadwell-DE FSP v1.0 support was dropped after 4.11.
## Required blobs
Mono Lake server OSF solution requires:
- [FSP] blob: SysPro custom FSP is required to support the 16-core Broadwell-DE on Mono Lake
- Microcode: Available through github.com:otcshare/Intel-Generic-Microcode.git
- ME binary: Available under NDA with Intel
## Payload
- LinuxBoot: Linuxboot is the prefered coreboot payload for Mono Lake.
It can be built following [All about u-root].
Tested configuration:
Linux Kernel v5.10.44
[u-root Mono Lake pull request]
u-root build command:
GO111MODULE=off u-root -build=bb -uinitcmd=systemboot \
-files="${FLASHROMDIR}/flashrom:bin/flashrom" \
-files="${VPDDIR}/vpd:bin/vpd" \
core github.com/u-root/u-root/cmds/boot/{systemboot,pxeboot,boot} \
github.com/u-root/u-root/cmds/exp/{cbmem,dmidecode,modprobe,ipmidump,netbootxyz} \
note: flashrom and vpd binaries must be precompiled
## Flashing coreboot
Mono Lake in-band BIOS firmware image update uses [flashrom]:
flashrom -p internal:ich_spi_mode=hwseq -c "Opaque flash chip" --ifd \
-i bios --noverify-all -w <path to coreboot image>
Yosemite-V1 OpenBMC BIOS firmware image update uses fw-util:
fw-util slotx --update bios <path to coreboot image>
## Yosimite-V1 server controls
To power off/on a Mono Lake host:
power-util slotx off
power-util slotx on
To connect to coreboot and Linux console through SOL (Serial Over Lan):
sol-util slotx
## Firmware configurations
[ChromeOS VPD] is used to store most of the firmware configurations.
RO_VPD region holds default values, while RW_VPD region holds customized
values.
VPD variables supported are:
- firmware_version: This variable holds overall firmware version. coreboot
uses that value to populate smbios type 1 version field.
- bmc_bootorder_override: When it's set to 1 IPMI OEM command can override boot
order. The boot order override is done in the u-root LinuxBoot payload.
- systemboot_log_level: u-root package systemboot log levels, would be mapped to
quiet/verbose in systemboot as that is all we have for now. 5 to 8 would be
mapped to verbose, 0 to 4 and 9 would be mapped to quiet.
- VPDs affecting coreboot are in src/mainboard/ocp/monolake/mainboard.c.
No coreboot VPD are required, uses safe defaults.
## Working features
The solution is developed using LinuxBoot payload with Linux kernel 5.2.9,
and [u-root] as initramfs.
- BMC integration:
- BMC readiness check
- IPMI commands
- watchdog timer
- POST complete pin acknowledgement
- Check BMC version: ipmidump -device
- Early serial output
- ACPI tables: DMAR/DSDT/FACP/FACS/HPET/MCFG/SPMI/SRAT/SLIT/SSDT/XSDT
- FSP MRC cache support (Skipping memory training upon subsequent reboots)
- Versions
- Check FSP version: cbmem | grep LB_TAG_PLATFORM_BLOB_VERSION
- Check Microcode version: cat /proc/cpuinfo | grep microcode
- Devices:
- Boot drive
- All 5 data drives
- NIC card
- SMBIOS:
- Type 0 BIOS Information
- Type 1 System Information
- Type 2 Baseboard Information
- Type 3 System Enclosure or Chassis
- Type 4 Processor Information
- Type 7 Cache Information
- Type 16 Physical Memory Array
- Type 17 Memory Device
- Type 32 System Boot Information
- Type 38 IPMI Device Information
- Type 41 Onboard Devices Extended Information
- Type 127 End-of-Table
- Power button
- u-root boot
- u-root pxeboot
## Stress and Performance tests passed
## Known issues
### Feature gaps
- flashrom command not able to update ME region
- ACPI BERT table
- PCIe hotplug through VPP (Virtual Pin Ports)
- RO_VPD region as well as other RO regions are not write protected
- Not able to selectively enable/disable core
## Technology
```eval_rst
+------------------------+---------------------------------------------+
| Processor (1 socket) | Broadwell-DE |
+------------------------+---------------------------------------------+
| BMC | Aspeed AST 1250 |
+------------------------+---------------------------------------------+
```
[OCP]: https://www.opencompute.org
[introduced Yosemite]: https://engineering.fb.com/2015/03/10/core-data/introducing-yosemite-the-first-open-source-modular-chassis-for-high-powered-microservers/
[Mono Lake was accepted]: https://www.opencompute.org/contributions?query=Tioga%20Pass%20v1.0
[FSP]: https://doc.coreboot.org/soc/intel/fsp/index.html
[u-root Mono Lake pull request]: https://github.com/u-root/u-root/pull/2045
[flashrom]: https://flashrom.org/Flashrom
[All about u-root]: https://github.com/linuxboot/book/tree/master/u-root
[u-root]: https://u-root.org/
[ChromeOS VPD]: https://chromium.googlesource.com/chromiumos/platform/vpd/+/master/README.md

View file

@ -159,7 +159,7 @@ ws_to_under=$(shell echo '$1' | tr ' \t' '_')
#######################################################################
# Helper functions for ramstage postprocess
spc :=
spc +=
spc := $(spc) $(spc)
comma := ,
# Returns all files and dirs below `dir` (recursively).
@ -261,7 +261,16 @@ EMPTY_RESOURCE_TEMPLATE_WARNING = 3150
# Redundant offset remarks are not useful in any way and are masking useful
# ones that might indicate an issue so it is better to hide them.
REDUNDANT_OFFSET_REMARK = 2158
# Ignore _HID & _ADR coexisting in Intel Lynxpoint and Broadwell ASL code.
# See cb:38803 & cb:38802
# "Multiple types (Device object requires either a _HID or _ADR, but not both)"
MULTIPLE_TYPES_WARNING = 3073
ifeq ($(CONFIG_SOUTHBRIDGE_INTEL_LYNXPOINT)$(CONFIG_SOC_INTEL_BROADWELL),y)
IGNORED_IASL_WARNINGS = -vw $(EMPTY_RESOURCE_TEMPLATE_WARNING) -vw $(REDUNDANT_OFFSET_REMARK) -vw $(MULTIPLE_TYPES_WARNING)
else
IGNORED_IASL_WARNINGS = -vw $(EMPTY_RESOURCE_TEMPLATE_WARNING) -vw $(REDUNDANT_OFFSET_REMARK)
endif
define asl_template
$(CONFIG_CBFS_PREFIX)/$(1).aml-file = $(obj)/$(1).aml
@ -469,7 +478,7 @@ ADAFLAGS_common += -gnatwa.eeD.HHTU.U.W.Y
# Disable style checks for now
ADAFLAGS_common += -gnatyN
LDFLAGS_common := --gc-sections -nostdlib -nostartfiles -static --emit-relocs
LDFLAGS_common := --gc-sections -nostdlib --nmagic -static --emit-relocs
ifeq ($(CONFIG_WARNINGS_ARE_ERRORS),y)
CFLAGS_common += -Werror

View file

@ -0,0 +1,8 @@
# Not meant for actual use. Exercises Intel TXT code. Since BIOS
# and SINIT ACM blobs are missing, use something else as placeholder.
CONFIG_VENDOR_PURISM=y
CONFIG_BOARD_PURISM_LIBREM15_V4=y
CONFIG_INTEL_TXT=y
CONFIG_INTEL_TXT_BIOSACM_FILE="3rdparty/blobs/cpu/intel/stm/stm.bin"
CONFIG_INTEL_TXT_SINITACM_FILE="3rdparty/blobs/cpu/intel/stm/stm.bin"
CONFIG_INTEL_TXT_LOGGING=y

4
configs/config.stm Normal file
View file

@ -0,0 +1,4 @@
CONFIG_VENDOR_PURISM=y
CONFIG_BOARD_PURISM_LIBREM15_V4=y
CONFIG_STM=y
CONFIG_IED_REGION_SIZE=0

View file

@ -730,6 +730,16 @@ config SMBIOS_ENCLOSURE_TYPE
convertible, or tablet enclosure will be used if the appropriate
system type is selected.
config VPD_SMBIOS_VERSION
bool "Populates SMBIOS type 0 version from the VPD_RO variable 'firmware_version'"
default n
depends on VPD && GENERATE_SMBIOS_TABLES
help
Selecting this option will read firmware_version from
VPD_RO and override SMBIOS type 0 version. One special
scenario of using this feature is to assign a BIOS version
to a coreboot image without the need to rebuild from source.
endmenu
source "payloads/Kconfig"
@ -1021,6 +1031,13 @@ config DEBUG_SPI_FLASH
help
This option enables additional SPI flash related debug messages.
config DEBUG_IPMI
bool "Output verbose IPMI debug messages"
default n
depends on IPMI_KCS
help
This option enables additional IPMI related debug messages.
if SOUTHBRIDGE_INTEL_BD82X6X && DEFAULT_CONSOLE_LOGLEVEL_8
# Only visible with the right southbridge and loglevel.
config DEBUG_INTEL_ME

View file

@ -18,4 +18,11 @@
#define ROM_DATA_SEG 0x10
#define ROM_CODE_SEG64 0x18
/*
* This define is placed here to make sure future romstage programmers
* know about it.
* It is used for STM setup code.
*/
#define SMM_TASK_STATE_SEG 0x20
#endif /* ROM_SEGS_H */

View file

@ -228,8 +228,6 @@ void run_postcar_phase(struct postcar_frame *pcf)
/* As postcar exist, it's end of romstage here */
timestamp_add_now(TS_END_ROMSTAGE);
console_time_report();
prog_set_arg(&prog, cbmem_top());
prog_run(&prog);

View file

@ -32,6 +32,8 @@
#if CONFIG(CHROMEOS)
#include <vendorcode/google/chromeos/gnvs.h>
#endif
#include <drivers/vpd/vpd.h>
#include <stdlib.h>
#define update_max(len, max_len, stmt) \
do { \
@ -381,12 +383,64 @@ static int create_smbios_type17_for_dimm(struct dimm_info *dimm,
return t->length + smbios_string_table_len(t->eos);
}
#define VERSION_VPD "firmware_version"
static const char *vpd_get_bios_version(void)
{
int size;
const char *s;
char *version;
s = vpd_find(VERSION_VPD, &size, VPD_RO);
if (!s) {
printk(BIOS_ERR, "Find version from VPD %s failed\n", VERSION_VPD);
return NULL;
}
version = malloc(size + 1);
if (!version) {
printk(BIOS_ERR, "Failed to malloc %d bytes for VPD version\n", size + 1);
return NULL;
}
memcpy(version, s, size);
version[size] = '\0';
printk(BIOS_DEBUG, "Firmware version %s from VPD %s\n", version, VERSION_VPD);
return version;
}
static const char *get_bios_version(void)
{
const char *s;
#define SPACES \
" "
if (CONFIG(CHROMEOS))
return SPACES;
if (CONFIG(VPD_SMBIOS_VERSION)) {
s = vpd_get_bios_version();
if (s != NULL)
return s;
}
s = smbios_mainboard_bios_version();
if (s != NULL)
return s;
if (strlen(CONFIG_LOCALVERSION) != 0) {
printk(BIOS_DEBUG, "BIOS version set to CONFIG_LOCALVERSION: '%s'\n",
CONFIG_LOCALVERSION);
return CONFIG_LOCALVERSION;
}
printk(BIOS_DEBUG, "SMBIOS firmware version is set to coreboot_version: '%s'\n",
coreboot_version);
return coreboot_version;
}
const char *__weak smbios_mainboard_bios_version(void)
{
if (strlen(CONFIG_LOCALVERSION))
return CONFIG_LOCALVERSION;
else
return coreboot_version;
return NULL;
}
static int smbios_write_type0(unsigned long *current, int handle)
@ -400,27 +454,14 @@ static int smbios_write_type0(unsigned long *current, int 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 CONFIG(HAVE_ACPI_TABLES)
#if CONFIG(CHROMEOS) && 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 CONFIG(HAVE_ACPI_TABLES)
/* SMBIOS offsets start at 1 rather than 0 */
chromeos_get_chromeos_acpi()->vbt10 =
(u32)t->eos + (version_offset - 1);
chromeos_get_chromeos_acpi()->vbt10 = (u32)t->eos + (version_offset - 1);
#endif
#endif /* CONFIG_CHROMEOS */
t->bios_version = smbios_add_string(t->eos, get_bios_version());
uint32_t rom_size = CONFIG_ROM_SIZE;
rom_size = MIN(CONFIG_ROM_SIZE, 16 * MiB);
t->bios_rom_size = (rom_size / 65535) - 1;
@ -657,7 +698,26 @@ static int smbios_write_type4(unsigned long *current, int handle)
t->processor_version = smbios_processor_name(t->eos);
t->processor_family = (res.eax > 0) ? 0x0c : 0x6;
t->processor_type = 3; /* System Processor */
t->core_count = (res.ebx >> 16) & 0xff;
/*
* If CPUID leaf 11 is available, calculate "core count" by dividing
* SMT_ID (logical processors in a core) by Core_ID (number of cores).
* This seems to be the way to arrive to a number of cores mentioned on
* ark.intel.com.
*/
if (cpu_have_cpuid() && cpuid_get_max_func() >= 0xb) {
uint32_t leaf_b_cores = 0, leaf_b_threads = 0;
res = cpuid_ext(0xb, 1);
leaf_b_cores = res.ebx;
res = cpuid_ext(0xb, 0);
leaf_b_threads = res.ebx;
/* if hyperthreading is not available, pretend this is 1 */
if (leaf_b_threads == 0) {
leaf_b_threads = 1;
}
t->core_count = leaf_b_cores / leaf_b_threads;
} else {
t->core_count = (res.ebx >> 16) & 0xff;
}
/* Assume we enable all the cores always, capped only by MAX_CPUS */
t->core_enabled = MIN(t->core_count, CONFIG_MAX_CPUS);
t->l1_cache_handle = 0xffff;

View file

@ -21,56 +21,14 @@
#include <smp/node.h>
#include <stddef.h>
#include <trace.h>
#include <timer.h>
#if (!defined(__PRE_RAM__) && CONFIG(HAVE_ROMSTAGE_CONSOLE_SPINLOCK)) || !CONFIG(HAVE_ROMSTAGE_CONSOLE_SPINLOCK)
DECLARE_SPIN_LOCK(console_lock)
#endif
#define TRACK_CONSOLE_TIME (CONFIG(HAVE_MONOTONIC_TIMER) && \
(ENV_RAMSTAGE || !CONFIG(CAR_GLOBAL_MIGRATION)))
static struct mono_time mt_start, mt_stop;
static long console_usecs;
static void console_time_run(void)
{
if (TRACK_CONSOLE_TIME)
timer_monotonic_get(&mt_start);
}
static void console_time_stop(void)
{
if (TRACK_CONSOLE_TIME) {
timer_monotonic_get(&mt_stop);
console_usecs += mono_time_diff_microseconds(&mt_start, &mt_stop);
}
}
void console_time_report(void)
{
if (!TRACK_CONSOLE_TIME)
return;
printk(BIOS_DEBUG, "Accumulated console time in " ENV_STRING " %ld ms\n",
DIV_ROUND_CLOSEST(console_usecs, USECS_PER_MSEC));
}
long console_time_get_and_reset(void)
{
if (!TRACK_CONSOLE_TIME)
return 0;
long elapsed = console_usecs;
console_usecs = 0;
return elapsed;
}
void do_putchar(unsigned char byte)
{
console_time_run();
console_tx_byte(byte);
console_time_stop();
}
static void wrap_putchar(unsigned char byte, void *data)
@ -103,8 +61,6 @@ int do_vprintk(int msg_level, const char *fmt, va_list args)
spin_lock(&console_lock);
#endif
console_time_run();
if (log_this == CONSOLE_LOG_FAST) {
i = vtxprintf(wrap_putchar_cbmemc, fmt, args, NULL);
} else {
@ -112,8 +68,6 @@ int do_vprintk(int msg_level, const char *fmt, va_list args)
console_tx_flush();
}
console_time_stop();
#ifdef __PRE_RAM__
#if CONFIG(HAVE_ROMSTAGE_CONSOLE_SPINLOCK)
spin_unlock(romstage_console_lock());

View file

@ -137,6 +137,14 @@ config SMM_STUB_STACK_SIZE
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

View file

@ -37,6 +37,8 @@
#include <timer.h>
#include <thread.h>
#include <security/intel/stm/SmmStm.h>
#define MAX_APIC_IDS 256
struct mp_callback {
@ -734,13 +736,39 @@ static void asmlinkage smm_do_relocation(void *arg)
* the location of the new SMBASE. If using SMM modules then this
* calculation needs to match that of the module loader.
*/
#if CONFIG(X86_SMM_LOADER_VERSION2)
perm_smbase = smm_get_cpu_smbase(cpu);
mp_state.perm_smbase = perm_smbase;
if (!perm_smbase) {
printk(BIOS_ERR, "%s: bad SMBASE for CPU %d\n", __func__, cpu);
return;
}
#else
perm_smbase = mp_state.perm_smbase;
perm_smbase -= cpu * runtime->save_state_size;
printk(BIOS_DEBUG, "New SMBASE 0x%08lx\n", perm_smbase);
#endif
/* Setup code checks this callback for validity. */
printk(BIOS_INFO, "%s : curr_smbase 0x%x perm_smbase 0x%x, cpu = %d\n",
__func__, (int)curr_smbase, (int)perm_smbase, cpu);
mp_state.ops.relocation_handler(cpu, curr_smbase, perm_smbase);
if (CONFIG(STM)) {
if (is_smm_enabled()) {
uintptr_t mseg;
size_t mseg_size;
smm_subregion(SMM_SUBREGION_MSEG, &mseg, &mseg_size);
stm_setup(mseg, p->cpu, runtime->num_cpus,
perm_smbase,
mp_state.perm_smbase,
runtime->start32_offset);
} else {
printk(BIOS_DEBUG,
"STM not loaded because SMM is not enabled!\n");
}
}
}
static void adjust_smm_apic_id_map(struct smm_loader_params *smm_params)
@ -754,9 +782,17 @@ static void adjust_smm_apic_id_map(struct smm_loader_params *smm_params)
static int install_relocation_handler(int num_cpus, size_t save_state_size)
{
int cpus = num_cpus;
#if CONFIG(X86_SMM_LOADER_VERSION2)
/* Default SMRAM size is not big enough to concurrently
* handle relocation for more than ~32 CPU threads
* therefore, relocate 1 by 1. */
cpus = 1;
#endif
struct smm_loader_params smm_params = {
.per_cpu_stack_size = CONFIG_SMM_STUB_STACK_SIZE,
.num_concurrent_stacks = num_cpus,
.num_concurrent_stacks = cpus,
.per_cpu_save_state_size = save_state_size,
.num_concurrent_save_states = 1,
.handler = smm_do_relocation,
@ -766,9 +802,10 @@ static int install_relocation_handler(int num_cpus, size_t save_state_size)
if (mp_state.ops.adjust_smm_params != NULL)
mp_state.ops.adjust_smm_params(&smm_params, 0);
if (smm_setup_relocation_handler(&smm_params))
if (smm_setup_relocation_handler(&smm_params)) {
printk(BIOS_ERR, "%s: smm setup failed\n", __func__);
return -1;
}
adjust_smm_apic_id_map(&smm_params);
return 0;
@ -777,8 +814,13 @@ static int install_relocation_handler(int num_cpus, size_t save_state_size)
static int install_permanent_handler(int num_cpus, uintptr_t smbase,
size_t smsize, size_t save_state_size)
{
/* There are num_cpus concurrent stacks and num_cpus concurrent save
* state areas. Lastly, set the stack size to 1KiB. */
/*
* All the CPUs will relocate to permanaent handler now. Set parameters
* needed for all CPUs. The placement of each CPUs entry point is
* determined by the loader. This code simply provides the beginning of
* SMRAM region, the number of CPUs who will use the handler, the stack
* size and save state size for each CPU.
*/
struct smm_loader_params smm_params = {
.per_cpu_stack_size = CONFIG_SMM_MODULE_STACK_SIZE,
.num_concurrent_stacks = num_cpus,
@ -790,7 +832,7 @@ static int install_permanent_handler(int num_cpus, uintptr_t smbase,
if (mp_state.ops.adjust_smm_params != NULL)
mp_state.ops.adjust_smm_params(&smm_params, 1);
printk(BIOS_DEBUG, "Installing SMM handler to 0x%08lx\n", smbase);
printk(BIOS_DEBUG, "Installing permanent SMM handler to 0x%08lx\n", smbase);
if (smm_load_module((void *)smbase, smsize, &smm_params))
return -1;
@ -1020,6 +1062,21 @@ static void fill_mp_state(struct mp_state *state, const struct mp_ops *ops)
ops->get_smm_info(&state->perm_smbase, &state->perm_smsize,
&state->smm_save_state_size);
/*
* Make sure there is enough room for the SMM descriptor
*/
if (CONFIG(STM))
state->smm_save_state_size +=
sizeof(TXT_PROCESSOR_SMM_DESCRIPTOR);
/* Currently, the CPU SMM save state size is based on a simplistic
* algorithm. (align on 4K)
* note: In the future, this will need to handle newer x86 processors
* that require alignment of the save state on 32K boundaries.
*/
state->smm_save_state_size =
ALIGN_UP(state->smm_save_state_size, 0x1000);
/*
* Default to smm_initiate_relocation() if trigger callback isn't
* provided.

View file

@ -11,7 +11,11 @@
## GNU General Public License for more details.
##
ifeq ($(CONFIG_X86_SMM_LOADER_VERSION2),y)
ramstage-y += smm_module_loaderv2.c
else
ramstage-y += smm_module_loader.c
endif
ifeq ($(CONFIG_ARCH_RAMSTAGE_X86_32),y)
$(eval $(call create_class_compiler,smm,x86_32))

View file

@ -17,6 +17,7 @@
#include <cpu/x86/cache.h>
#include <commonlib/helpers.h>
#include <console/console.h>
#include <security/intel/stm/SmmStm.h>
#define FXSAVE_SIZE 512
@ -173,8 +174,9 @@ static void smm_stub_place_staggered_entry_points(char *base,
* concurrent areas requested. The save state always lives at the top of SMRAM
* space, and the entry point is at offset 0x8000.
*/
static int smm_module_setup_stub(void *smbase, struct smm_loader_params *params,
void *fxsave_area)
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;
@ -201,6 +203,8 @@ static int smm_module_setup_stub(void *smbase, struct smm_loader_params *params,
/* 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)
return -1;
size -= total_save_state_size;
/* The save state size encroached over the first SMM entry point. */
@ -266,7 +270,9 @@ static int smm_module_setup_stub(void *smbase, struct smm_loader_params *params,
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;
/* Initialize the APIC id to CPU number table to be 1:1 */
for (i = 0; i < params->num_concurrent_stacks; i++)
@ -305,14 +311,20 @@ int smm_setup_relocation_handler(struct smm_loader_params *params)
if (params->num_concurrent_stacks == 0)
params->num_concurrent_stacks = CONFIG_MAX_CPUS;
return smm_module_setup_stub(smram, params, fxsave_area_relocation);
return smm_module_setup_stub(smram, SMM_DEFAULT_SIZE,
params, fxsave_area_relocation);
}
/* The SMM module is placed within the provided region in the following
* manner:
* +-----------------+ <- smram + size
* | BIOS resource |
* | list (STM) |
* +-----------------+ <- smram + size - CONFIG_BIOS_RESOURCE_LIST_SIZE
* | stacks |
* +-----------------+ <- smram + size - total_stack_size
* +-----------------+ <- .. - total_stack_size
* | fxsave area |
* +-----------------+ <- .. - total_stack_size - fxsave_size
* | ... |
* +-----------------+ <- smram + handler_size + SMM_DEFAULT_SIZE
* | handler |
@ -354,6 +366,10 @@ int smm_load_module(void *smram, size_t size, struct smm_loader_params *params)
/* Stacks start at the top of the region. */
base = smram;
base += size;
if (CONFIG(STM))
base -= CONFIG_BIOS_RESOURCE_LIST_SIZE;
params->stack_top = base;
/* SMM module starts at offset SMM_DEFAULT_SIZE with the load alignment
@ -382,6 +398,7 @@ int smm_load_module(void *smram, size_t size, struct smm_loader_params *params)
/* Does the required amount of memory exceed the SMRAM region size? */
total_size = total_stack_size + handler_size;
total_size += fxsave_size + SMM_DEFAULT_SIZE;
if (total_size > size)
return -1;
@ -391,5 +408,5 @@ int smm_load_module(void *smram, size_t size, struct smm_loader_params *params)
params->handler = rmodule_entry(&smm_mod);
params->handler_arg = rmodule_parameters(&smm_mod);
return smm_module_setup_stub(smram, params, fxsave_area);
return smm_module_setup_stub(smram, size, params, fxsave_area);
}

View file

@ -0,0 +1,666 @@
/*
* 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 <stdint.h>
#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>
#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;
uintptr_t smbase;
uintptr_t entry;
uintptr_t ss_start;
uintptr_t code_start;
uintptr_t 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 + 0x8000
* 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(uintptr_t 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__);
return 0;
}
stub_size = rmodule_memory_size(&smm_stub);
/* How many CPUs can fit into one 64K 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 allowed 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__);
printk(BIOS_ERR, " save state & stub size need to be reduced\n");
printk(BIOS_ERR, " or increase SMRAM size\n");
return 0;
}
if (sizeof(cpus) / sizeof(struct cpu_smm_info) < num_cpus) {
printk(BIOS_ERR,
"%s: increase MAX_CPUS in Kconfig\n", __func__);
return 0;
}
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 %zx entry %zx\n",
cpus[i].smbase, cpus[i].entry);
printk(BIOS_DEBUG,
" ss_start %zx code_end %zx\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
*/
u32 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 because
* the appropriate smi handling code was not installed
*/
static int smm_place_entry_code(uintptr_t 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: stack encroachment\n", __func__);
printk(BIOS_ERR, "%s: smbase %zx, stack_top %x\n",
__func__, cpus[num_cpus].smbase, stack_top);
return 0;
}
}
} else {
printk(BIOS_ERR, "%s: unable to place smm entry code\n", __func__);
return 0;
}
printk(BIOS_INFO, "%s: smbase %zx, 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 %zx, cpu # 0x%x\n",
cpus[i].code_start, i);
printk(BIOS_DEBUG, "%s: copying from %zx to %zx 0x%x bytes\n",
__func__, cpus[0].code_start, cpus[i].code_start, size);
}
return 1;
}
/*
* 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: %zx : stack space: needed -> %zx\n",
__func__, params->num_concurrent_stacks,
total_stack_size);
printk(BIOS_DEBUG, " available -> %zx : per_cpu_stack_size : %zx\n",
size, 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 %p\n", __func__, 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 int smm_stub_place_staggered_entry_points(char *base,
const struct smm_loader_params *params, const struct rmodule *smm_stub)
{
size_t stub_entry_offset;
int rc = 1;
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) {
rc = smm_place_entry_code((unsigned int)base,
params->num_concurrent_save_states,
(unsigned int)params->stack_top, params);
}
return rc;
}
/*
* 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 smm stack 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 (0x30000) 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 -> %zx:available->%zx\n",
__func__, total_save_state_size, 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: %zx : smm_entry_offset -> %x\n",
__func__, 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 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 -> %p : available -> %zx\n", __func__,
base, 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;
}
if (!smm_stub_place_staggered_entry_points(base, params, &smm_stub)) {
printk(BIOS_ERR, "%s: staggered entry points failed\n", __func__);
return -1;
}
/* 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__, stub_params->runtime.smbase);
printk(BIOS_DEBUG,
"%s: stack_top = 0x%x\n", __func__, stub_params->stack_top);
printk(BIOS_DEBUG, "%s: stack_size = 0x%x\n",
__func__, stub_params->stack_size);
printk(BIOS_DEBUG, "%s: runtime.smbase = 0x%x\n",
__func__, stub_params->runtime.smbase);
printk(BIOS_DEBUG, "%s: runtime.start32_offset = 0x%x\n", __func__,
stub_params->runtime.start32_offset);
printk(BIOS_DEBUG, "%s: runtime.smm_size = 0x%zx\n",
__func__, smm_size);
printk(BIOS_DEBUG, "%s: per_cpu_save_state_size = 0x%x\n",
__func__, stub_params->runtime.save_state_size);
printk(BIOS_DEBUG, "%s: num_cpus = 0x%x\n", __func__,
stub_params->runtime.num_cpus);
printk(BIOS_DEBUG, "%s: total_save_state_size = 0x%x\n",
__func__, (stub_params->runtime.save_state_size *
stub_params->runtime.num_cpus));
total_size_all = stub_params->stack_size +
(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_BIOS_RESOURCE_LIST_SIZE;
total_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 %zx, available -> %zx\n",
__func__, total_size, 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 = %zx\n",
__func__, 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%p\n",
__func__, smram);
printk(BIOS_DEBUG, "%s: smram_end: %p\n",
__func__, smram + size);
printk(BIOS_DEBUG, "%s: stack_top: %p\n",
__func__, params->stack_top);
printk(BIOS_DEBUG, "%s: handler start %p\n",
__func__, params->handler);
printk(BIOS_DEBUG, "%s: handler_size %zx\n",
__func__, handler_size);
printk(BIOS_DEBUG, "%s: handler_arg %p\n",
__func__, params->handler_arg);
printk(BIOS_DEBUG, "%s: fxsave_area %p\n",
__func__, fxsave_area);
printk(BIOS_DEBUG, "%s: fxsave_size %zx\n",
__func__, fxsave_size);
printk(BIOS_DEBUG, "%s: CONFIG_MSEG_SIZE 0x%x\n",
__func__, CONFIG_MSEG_SIZE);
printk(BIOS_DEBUG, "%s: CONFIG_BIOS_RESOURCE_LIST_SIZE 0x%x\n",
__func__, 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: %p\n",
__func__, base);
params->smm_entry = (uintptr_t)base + params->smm_main_entry_offset;
return smm_module_setup_stub(base, size, params, fxsave_area);
}

View file

@ -42,8 +42,15 @@ fxsave_area_size:
smm_runtime:
smbase:
.long 0
smm_size:
.long 0
save_state_size:
.long 0
num_cpus:
.long 0
/* allows the STM to bring up SMM in 32-bit mode */
start32_offset:
.long smm_trampoline32 - _start
/* apic_to_cpu_num is a table mapping the default APIC id to CPU num. If the
* APIC id is found at the given index, the contiguous CPU number is index
* into the table. */
@ -90,6 +97,14 @@ smm_relocate_gdt:
/* gdt selector 0x10, flat data segment */
.word 0xffff, 0x0000
.byte 0x00, 0x93, 0xcf, 0x00
/* gdt selector 0x18, flat code segment (64-bit) */
.word 0xffff, 0x0000
.byte 0x00, 0x9b, 0xcf, 0x00
/* gdt selector 0x20 tss segment */
.word 0xffff, 0x0000
.byte 0x00, 0x8b, 0x80, 0x00
smm_relocate_gdt_end:
.align 4

View file

@ -17,6 +17,7 @@
#include <cpu/x86/smm.h>
#include <stage_cache.h>
#include <types.h>
#include <inttypes.h>
/*
* Subregions within SMM
@ -25,6 +26,8 @@
* +-------------------------+
* | External Stage Cache | SMM_RESERVED_SIZE
* +-------------------------+
* | STM | MSEG_SIZE
* +-------------------------+
* | code and data |
* | (TSEG) |
* +-------------------------+ TSEG
@ -35,17 +38,24 @@ int smm_subregion(int sub, uintptr_t *start, size_t *size)
size_t sub_size;
const size_t ied_size = CONFIG_IED_REGION_SIZE;
const size_t cache_size = CONFIG_SMM_RESERVED_SIZE;
const size_t mseg_size = CONFIG_MSEG_SIZE;
smm_region(&sub_base, &sub_size);
ASSERT(IS_ALIGNED(sub_base, sub_size));
ASSERT(sub_size > (cache_size + ied_size));
ASSERT(sub_size > (cache_size + ied_size + mseg_size));
switch (sub) {
case SMM_SUBREGION_HANDLER:
/* Handler starts at the base of TSEG. */
sub_size -= ied_size;
sub_size -= cache_size;
sub_size -= mseg_size;
break;
case SMM_SUBREGION_MSEG:
/* MSEG follows the SMM HANDLER subregion */
sub_base += sub_size - (ied_size + cache_size + mseg_size);
sub_size = mseg_size;
break;
case SMM_SUBREGION_CACHE:
/* External cache is in the middle of TSEG. */
@ -88,11 +98,11 @@ void smm_list_regions(void)
return;
printk(BIOS_DEBUG, "SMM Memory Map\n");
printk(BIOS_DEBUG, "SMRAM : 0x%zx 0x%zx\n", base, size);
printk(BIOS_DEBUG, "SMRAM : 0x%" PRIxPTR " 0x%zx\n", base, size);
for (i = 0; i < SMM_SUBREGION_NUM; i++) {
if (smm_subregion(i, &base, &size))
continue;
printk(BIOS_DEBUG, " Subregion %d: 0x%zx 0x%zx\n", i, base, size);
printk(BIOS_DEBUG, " Subregion %d: 0x%" PRIxPTR " 0x%zx\n", i, base, size);
}
}

View file

@ -8,3 +8,22 @@ config IPMI_KCS_REGISTER_SPACING
depends on IPMI_KCS
help
KCS status and command register IO port address spacing
config IPMI_FRU_SINGLE_RW_SZ
int
default 16
depends on IPMI_KCS
help
The data size in a single IPMI FRU read/write command.
IPMB messages are limited to 32-bytes total. When the
data size is larger than this value, IPMI can complete
reading/writing the data over multiple commands.
config IPMI_KCS_TIMEOUT_MS
int
default 5000
depends on IPMI_KCS
help
The time unit is millisecond for each IPMI KCS transfer.
IPMI spec v2.0 rev 1.1 Sec. 9.15, a five-second timeout or
greater is recommended.

View file

@ -1,3 +1,4 @@
ramstage-$(CONFIG_IPMI_KCS) += ipmi_kcs.c
ramstage-$(CONFIG_IPMI_KCS) += ipmi_kcs_ops.c
ramstage-$(CONFIG_IPMI_KCS) += ipmi_ops.c
ramstage-$(CONFIG_IPMI_KCS) += ipmi_fru.c

411
src/drivers/ipmi/ipmi_fru.c Normal file
View file

@ -0,0 +1,411 @@
/*
* This file is part of the coreboot project.
*
* Copyright (C) 2019 Wiwynn 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 <console/console.h>
#include <string.h>
#include <delay.h>
#include <stdlib.h>
#include "ipmi_ops.h"
#define MAX_FRU_BUSY_RETRY 5
#define READ_FRU_DATA_RETRY_INTERVAL_MS 30 /* From IPMI spec v2.0 rev 1.1 */
#define OFFSET_LENGTH_MULTIPLIER 8 /* offsets/lengths are multiples of 8 */
#define NUM_DATA_BYTES(t) (t & 0x3f) /* Encoded in type/length byte */
static enum cb_err ipmi_read_fru(const int port, struct ipmi_read_fru_data_req *req,
uint8_t *fru_data)
{
int ret;
uint8_t total_size;
uint16_t offset = 0;
struct ipmi_read_fru_data_rsp rsp;
int retry_count = 0;
if (req == NULL || fru_data == NULL) {
printk(BIOS_ERR, "%s failed, null pointer parameter\n",
__func__);
return CB_ERR;
}
total_size = req->count;
do {
if (req->count > CONFIG_IPMI_FRU_SINGLE_RW_SZ)
req->count = CONFIG_IPMI_FRU_SINGLE_RW_SZ;
while (retry_count <= MAX_FRU_BUSY_RETRY) {
ret = ipmi_kcs_message(port, IPMI_NETFN_STORAGE, 0x0,
IPMI_READ_FRU_DATA, (const unsigned char *) req,
sizeof(*req), (unsigned char *) &rsp, sizeof(rsp));
if (rsp.resp.completion_code == 0x81) {
/* Device is busy */
if (retry_count == MAX_FRU_BUSY_RETRY) {
printk(BIOS_ERR, "IPMI: %s command failed, "
"device busy timeout\n", __func__);
return CB_ERR;
}
printk(BIOS_ERR, "IPMI: FRU device is busy, "
"retry count:%d\n", retry_count);
retry_count++;
mdelay(READ_FRU_DATA_RETRY_INTERVAL_MS);
} else if (ret < sizeof(struct ipmi_rsp) || rsp.resp.completion_code) {
printk(BIOS_ERR, "IPMI: %s command failed (ret=%d resp=0x%x)\n",
__func__, ret, rsp.resp.completion_code);
return CB_ERR;
}
break;
}
retry_count = 0;
memcpy(fru_data + offset, rsp.data, rsp.count);
offset += rsp.count;
total_size -= rsp.count;
req->fru_offset += rsp.count;
req->count = total_size;
} while (total_size > 0);
return CB_SUCCESS;
}
/* data: data to check, offset: offset to checksum. */
static uint8_t checksum(uint8_t *data, int offset)
{
uint8_t c = 0;
for (; offset > 0; offset--, data++)
c += *data;
return -c;
}
static uint8_t data2str(const uint8_t *frudata, char *stringdata, uint8_t length)
{
uint8_t type;
/* bit[7:6] is the type code. */
type = ((frudata[0] & 0xc0) >> 6);
if (type != ASCII_8BIT) {
printk(BIOS_ERR, "%s typecode %d is unsupported, FRU string only "
"supports 8-bit ASCII + Latin 1 for now.\n", __func__, type);
return 0;
}
/* In the spec the string data is always the next byte to the type/length byte. */
memcpy(stringdata, frudata + 1, length);
stringdata[length] = '\0';
return length;
}
static void read_fru_board_info_area(const int port, const uint8_t id,
uint8_t offset, struct fru_board_info *info)
{
uint8_t length;
struct ipmi_read_fru_data_req req;
uint8_t *data_ptr;
offset = offset * OFFSET_LENGTH_MULTIPLIER;
if (!offset)
return;
req.fru_device_id = id;
/* Read Board Info Area length first. */
req.fru_offset = offset + 1;
req.count = sizeof(length);
if (ipmi_read_fru(port, &req, &length) != CB_SUCCESS || !length) {
printk(BIOS_ERR, "%s failed, length: %d\n", __func__, length);
return;
}
length = length * OFFSET_LENGTH_MULTIPLIER;
data_ptr = (uint8_t *)malloc(length);
if (!data_ptr) {
printk(BIOS_ERR, "malloc %d bytes for board info failed\n", length);
return;
}
/* Read Board Info Area data. */
req.fru_offset = offset;
req.count = length;
if (ipmi_read_fru(port, &req, data_ptr) != CB_SUCCESS) {
printk(BIOS_ERR, "%s failed to read fru\n", __func__);
goto out;
}
if (checksum(data_ptr, length)) {
printk(BIOS_ERR, "Bad FRU board info checksum.\n");
goto out;
}
/* Read manufacturer string, bit[5:0] is the string length. */
length = NUM_DATA_BYTES(data_ptr[BOARD_MAN_TYPE_LEN_OFFSET]);
data_ptr += BOARD_MAN_TYPE_LEN_OFFSET;
if (length > 0) {
info->manufacturer = malloc(length + 1);
if (!info->manufacturer) {
printk(BIOS_ERR, "%s failed to malloc %d bytes for "
"manufacturer.\n", __func__, length + 1);
goto out;
}
if (!data2str((const uint8_t *)data_ptr, info->manufacturer, length))
free(info->manufacturer);
}
/* Read product name string. */
data_ptr += length + 1;
length = NUM_DATA_BYTES(data_ptr[0]);
if (length > 0) {
info->product_name = malloc(length+1);
if (!info->product_name) {
printk(BIOS_ERR, "%s failed to malloc %d bytes for "
"product_name.\n", __func__, length + 1);
goto out;
}
if (!data2str((const uint8_t *)data_ptr, info->product_name, length))
free(info->product_name);
}
/* Read serial number string. */
data_ptr += length + 1;
length = NUM_DATA_BYTES(data_ptr[0]);
if (length > 0) {
info->serial_number = malloc(length + 1);
if (!info->serial_number) {
printk(BIOS_ERR, "%s failed to malloc %d bytes for "
"serial_number.\n", __func__, length + 1);
goto out;
}
if (!data2str((const uint8_t *)data_ptr, info->serial_number, length))
free(info->serial_number);
}
/* Read part number string. */
data_ptr += length + 1;
length = NUM_DATA_BYTES(data_ptr[0]);
if (length > 0) {
info->part_number = malloc(length + 1);
if (!info->part_number) {
printk(BIOS_ERR, "%s failed to malloc %d bytes for "
"part_number.\n", __func__, length + 1);
goto out;
}
if (!data2str((const uint8_t *)data_ptr, info->part_number, length))
free(info->part_number);
}
out:
free(data_ptr);
}
static void read_fru_product_info_area(const int port, const uint8_t id,
uint8_t offset, struct fru_product_info *info)
{
uint8_t length;
struct ipmi_read_fru_data_req req;
uint8_t *data_ptr;
offset = offset * OFFSET_LENGTH_MULTIPLIER;
if (!offset)
return;
req.fru_device_id = id;
/* Read Product Info Area length first. */
req.fru_offset = offset + 1;
req.count = sizeof(length);
if (ipmi_read_fru(port, &req, &length) != CB_SUCCESS || !length) {
printk(BIOS_ERR, "%s failed, length: %d\n", __func__, length);
return;
}
length = length * OFFSET_LENGTH_MULTIPLIER;
data_ptr = (uint8_t *)malloc(length);
if (!data_ptr) {
printk(BIOS_ERR, "malloc %d bytes for product info failed\n", length);
return;
}
/* Read Product Info Area data. */
req.fru_offset = offset;
req.count = length;
if (ipmi_read_fru(port, &req, data_ptr) != CB_SUCCESS) {
printk(BIOS_ERR, "%s failed to read fru\n", __func__);
goto out;
}
if (checksum(data_ptr, length)) {
printk(BIOS_ERR, "Bad FRU product info checksum.\n");
goto out;
}
/* Read manufacturer string, bit[5:0] is the string length. */
length = NUM_DATA_BYTES(data_ptr[PRODUCT_MAN_TYPE_LEN_OFFSET]);
data_ptr += PRODUCT_MAN_TYPE_LEN_OFFSET;
if (length > 0) {
info->manufacturer = malloc(length + 1);
if (!info->manufacturer) {
printk(BIOS_ERR, "%s failed to malloc %d bytes for "
"manufacturer.\n", __func__, length + 1);
goto out;
}
if (!data2str((const uint8_t *)data_ptr, info->manufacturer, length))
free(info->manufacturer);
}
/* Read product_name string. */
data_ptr += length + 1;
length = NUM_DATA_BYTES(data_ptr[0]);
if (length > 0) {
info->product_name = malloc(length + 1);
if (!info->product_name) {
printk(BIOS_ERR, "%s failed to malloc %d bytes for "
"product_name.\n", __func__, length + 1);
goto out;
}
if (!data2str((const uint8_t *)data_ptr, info->product_name, length))
free(info->product_name);
}
/* Read product part/model number. */
data_ptr += length + 1;
length = NUM_DATA_BYTES(data_ptr[0]);
if (length > 0) {
info->product_partnumber = malloc(length + 1);
if (!info->product_partnumber) {
printk(BIOS_ERR, "%s failed to malloc %d bytes for "
"product_partnumber.\n", __func__, length + 1);
goto out;
}
if (!data2str((const uint8_t *)data_ptr, info->product_partnumber, length))
free(info->product_partnumber);
}
/* Read product version string. */
data_ptr += length + 1;
length = NUM_DATA_BYTES(data_ptr[0]);
if (length > 0) {
info->product_version = malloc(length + 1);
if (!info->product_version) {
printk(BIOS_ERR, "%s failed to malloc %d bytes for "
"product_version.\n", __func__, length + 1);
goto out;
}
if (!data2str((const uint8_t *)data_ptr, info->product_version, length))
free(info->product_version);
}
/* Read serial number string. */
data_ptr += length + 1;
length = NUM_DATA_BYTES(data_ptr[0]);
if (length > 0) {
info->serial_number = malloc(length + 1);
if (!info->serial_number) {
printk(BIOS_ERR, "%s failed to malloc %d bytes for "
"serial_number.\n", __func__, length + 1);
goto out;
}
if (!data2str((const uint8_t *)data_ptr, info->serial_number, length))
free(info->serial_number);
}
/* Read asset tag string. */
data_ptr += length + 1;
length = NUM_DATA_BYTES(data_ptr[0]);
if (length > 0) {
info->asset_tag = malloc(length + 1);
if (!info->asset_tag) {
printk(BIOS_ERR, "%s failed to malloc %d bytes for "
"asset_tag.\n", __func__, length + 1);
goto out;
}
if (!data2str((const uint8_t *)data_ptr, info->asset_tag, length))
free(info->asset_tag);
}
out:
free(data_ptr);
}
void read_fru_areas(const int port, const uint8_t id, uint16_t offset,
struct fru_info_str *fru_info_str)
{
struct ipmi_read_fru_data_req req;
struct ipmi_fru_common_hdr fru_common_hdr;
/* Set all the char pointers to 0 first, to avoid mainboard
* overwriting SMBIOS string with any non-NULL char pointer
* by accident. */
memset(fru_info_str, 0, sizeof(*fru_info_str));
req.fru_device_id = id;
req.fru_offset = offset;
req.count = sizeof(fru_common_hdr);
/* Read FRU common header first */
if (ipmi_read_fru(port, &req, (uint8_t *)&fru_common_hdr) == CB_SUCCESS) {
if (checksum((uint8_t *)&fru_common_hdr, sizeof(fru_common_hdr))) {
printk(BIOS_ERR, "Bad FRU common header checksum.\n");
return;
}
printk(BIOS_DEBUG, "FRU common header: format_version: %x\n"
"product_area_offset: %x\n"
"board_area_offset: %x\n"
"chassis_area_offset: %x\n",
fru_common_hdr.format_version,
fru_common_hdr.product_area_offset,
fru_common_hdr.board_area_offset,
fru_common_hdr.chassis_area_offset);
} else {
printk(BIOS_ERR, "Read FRU common header failed\n");
return;
}
read_fru_product_info_area(port, id, fru_common_hdr.product_area_offset,
&fru_info_str->prod_info);
read_fru_board_info_area(port, id, fru_common_hdr.board_area_offset,
&fru_info_str->board_info);
/* ToDo: Add read_fru_chassis_info_area(). */
}
void read_fru_one_area(const int port, const uint8_t id, uint16_t offset,
struct fru_info_str *fru_info_str, enum fru_area fru_area)
{
struct ipmi_read_fru_data_req req;
struct ipmi_fru_common_hdr fru_common_hdr;
req.fru_device_id = id;
req.fru_offset = offset;
req.count = sizeof(fru_common_hdr);
if (ipmi_read_fru(port, &req, (uint8_t *)&fru_common_hdr) == CB_SUCCESS) {
if (checksum((uint8_t *)&fru_common_hdr, sizeof(fru_common_hdr))) {
printk(BIOS_ERR, "Bad FRU common header checksum.\n");
return;
}
printk(BIOS_DEBUG, "FRU common header: format_version: %x\n"
"product_area_offset: %x\n"
"board_area_offset: %x\n"
"chassis_area_offset: %x\n",
fru_common_hdr.format_version,
fru_common_hdr.product_area_offset,
fru_common_hdr.board_area_offset,
fru_common_hdr.chassis_area_offset);
} else {
printk(BIOS_ERR, "Read FRU common header failed\n");
return;
}
switch (fru_area) {
case PRODUCT_INFO_AREA:
memset(&fru_info_str->prod_info, 0, sizeof(fru_info_str->prod_info));
read_fru_product_info_area(port, id, fru_common_hdr.product_area_offset,
&fru_info_str->prod_info);
break;
case BOARD_INFO_AREA:
memset(&fru_info_str->board_info, 0, sizeof(fru_info_str->board_info));
read_fru_board_info_area(port, id, fru_common_hdr.board_area_offset,
&fru_info_str->board_info);
break;
/* ToDo: Add case for CHASSIS_INFO_AREA. */
default:
printk(BIOS_ERR, "Invalid fru_area: %d\n", fru_area);
break;
}
}

View file

@ -15,7 +15,7 @@
#include <console/console.h>
#include <device/device.h>
#include <arch/io.h>
#include <delay.h>
#include <timer.h>
#include "ipmi_kcs.h"
#define IPMI_KCS_STATE(_x) ((_x) >> 6)
@ -41,33 +41,29 @@
static unsigned char ipmi_kcs_status(int port)
{
unsigned char status = inb(IPMI_STAT(port));
printk(BIOS_SPEW, "%s: 0x%02x\n", __func__, status);
if (CONFIG(DEBUG_IPMI))
printk(BIOS_SPEW, "%s: 0x%02x\n", __func__, status);
return status;
}
static int wait_ibf_timeout(int port)
{
int timeout = 1000;
do {
if (!(ipmi_kcs_status(port) & IPMI_KCS_IBF))
return 0;
udelay(100);
} while (timeout--);
printk(BIOS_ERR, "wait_ibf timeout!\n");
return timeout;
if (!wait_ms(CONFIG_IPMI_KCS_TIMEOUT_MS, !(ipmi_kcs_status(port) & IPMI_KCS_IBF))) {
printk(BIOS_ERR, "wait_ibf timeout!\n");
return 1;
} else {
return 0;
}
}
static int wait_obf_timeout(int port)
{
int timeout = 1000;
do {
if ((ipmi_kcs_status(port) & IPMI_KCS_OBF))
return 0;
udelay(100);
} while (timeout--);
printk(BIOS_ERR, "wait_obf timeout!\n");
return timeout;
if (!wait_ms(CONFIG_IPMI_KCS_TIMEOUT_MS, (ipmi_kcs_status(port) & IPMI_KCS_OBF))) {
printk(BIOS_ERR, "wait_obf timeout!\n");
return 1;
} else {
return 0;
}
}
@ -75,7 +71,8 @@ static int ipmi_kcs_send_data_byte(int port, const unsigned char byte)
{
unsigned char status;
printk(BIOS_SPEW, "%s: 0x%02x\n", __func__, byte);
if (CONFIG(DEBUG_IPMI))
printk(BIOS_SPEW, "%s: 0x%02x\n", __func__, byte);
outb(byte, IPMI_DATA(port));
@ -98,7 +95,8 @@ static int ipmi_kcs_send_last_data_byte(int port, const unsigned char byte)
{
unsigned char status;
printk(BIOS_SPEW, "%s: 0x%02x\n", __func__, byte);
if (CONFIG(DEBUG_IPMI))
printk(BIOS_SPEW, "%s: 0x%02x\n", __func__, byte);
if (wait_ibf_timeout(port))
return 1;
@ -119,7 +117,8 @@ static int ipmi_kcs_send_last_data_byte(int port, const unsigned char byte)
static int ipmi_kcs_send_cmd_byte(int port, const unsigned char byte)
{
printk(BIOS_SPEW, "%s: 0x%02x\n", __func__, byte);
if (CONFIG(DEBUG_IPMI))
printk(BIOS_SPEW, "%s: 0x%02x\n", __func__, byte);
if (wait_ibf_timeout(port))
return 1;

View file

@ -22,9 +22,16 @@
#define IPMI_BMC_GET_DEVICE_ID 0x01
#define IPMI_IPMI_VERSION_MINOR(x) ((x) >> 4)
#define IPMI_IPMI_VERSION_MAJOR(x) ((x) & 0xf)
#define IPMI_BMC_GET_SELFTEST_RESULTS 0x04
#define IPMI_APP_SELFTEST_RESERVED 0xFF
#define IPMI_APP_SELFTEST_NO_ERROR 0x55
#define IPMI_APP_SELFTEST_NOT_IMPLEMENTED 0x56
#define IPMI_APP_SELFTEST_ERROR 0x57
#define IPMI_APP_SELFTEST_FATAL_HW_ERROR 0x58
#define IPMI_NETFN_FIRMWARE 0x08
#define IPMI_NETFN_STORAGE 0x0a
#define IPMI_READ_FRU_DATA 0x11
#define IPMI_NETFN_TRANSPORT 0x0c
#define IPMI_CMD_ACPI_POWERON 0x06
@ -52,4 +59,11 @@ struct ipmi_devid_rsp {
uint8_t product_id[2];
} __packed;
/* Get Self Test Results */
struct ipmi_selftest_rsp {
struct ipmi_rsp resp;
uint8_t result;
uint8_t param;
} __packed;
#endif

View file

@ -59,11 +59,34 @@ static int ipmi_get_device_id(struct device *dev, struct ipmi_devid_rsp *rsp)
return 0;
}
static int ipmi_get_bmc_self_test_result(struct device *dev, struct ipmi_selftest_rsp *rsp)
{
int ret;
ret = ipmi_kcs_message(dev->path.pnp.port, IPMI_NETFN_APPLICATION, 0,
IPMI_BMC_GET_SELFTEST_RESULTS, NULL, 0, (u8 *)rsp,
sizeof(*rsp));
if (ret < sizeof(struct ipmi_rsp) || rsp->resp.completion_code) {
printk(BIOS_ERR, "IPMI: %s command failed (ret=%d resp=0x%x)\n",
__func__, ret, rsp->resp.completion_code);
return 1;
}
if (ret != sizeof(*rsp)) {
printk(BIOS_ERR, "IPMI: %s response truncated\n", __func__);
return 1;
}
return 0;
}
static void ipmi_kcs_init(struct device *dev)
{
struct ipmi_devid_rsp rsp;
uint32_t man_id = 0, prod_id = 0;
struct drivers_ipmi_config *conf = NULL;
struct ipmi_selftest_rsp selftestrsp;
uint8_t retry_count;
if (!dev->enabled)
return;
@ -92,6 +115,42 @@ static void ipmi_kcs_init(struct device *dev)
}
}
printk(BIOS_INFO, "Get BMC self test result...");
for (retry_count = 0; retry_count < conf->bmc_boot_timeout; retry_count++) {
if (!ipmi_get_bmc_self_test_result(dev, &selftestrsp))
break;
mdelay(1000);
}
switch (selftestrsp.result) {
case IPMI_APP_SELFTEST_NO_ERROR: /* 0x55 */
printk(BIOS_DEBUG, "No Error\n");
break;
case IPMI_APP_SELFTEST_NOT_IMPLEMENTED: /* 0x56 */
printk(BIOS_DEBUG, "Function Not Implemented\n");
break;
case IPMI_APP_SELFTEST_ERROR: /* 0x57 */
printk(BIOS_ERR, "BMC: Corrupted or inaccessible data or device\n");
/* Don't write tables if communication failed */
dev->enabled = 0;
break;
case IPMI_APP_SELFTEST_FATAL_HW_ERROR: /* 0x58 */
printk(BIOS_ERR, "BMC: Fatal Hardware Error\n");
/* Don't write tables if communication failed */
dev->enabled = 0;
break;
case IPMI_APP_SELFTEST_RESERVED: /* 0xFF */
printk(BIOS_DEBUG, "Reserved\n");
break;
default: /* Other Device Specific Hardware Error */
printk(BIOS_ERR, "BMC: Device Specific Error\n");
/* Don't write tables if communication failed */
dev->enabled = 0;
break;
}
if (!ipmi_get_device_id(dev, &rsp)) {
/* Queried the IPMI revision from BMC */
ipmi_revision_minor = IPMI_IPMI_VERSION_MINOR(rsp.ipmi_version);

View file

@ -16,6 +16,7 @@
#include <console/console.h>
#include "ipmi_ops.h"
#include <string.h>
enum cb_err ipmi_init_and_start_bmc_wdt(const int port, uint16_t countdown,
uint8_t action)
@ -104,3 +105,28 @@ enum cb_err ipmi_stop_bmc_wdt(const int port)
return CB_SUCCESS;
}
enum cb_err ipmi_get_system_guid(const int port, uint8_t *uuid)
{
int ret;
struct ipmi_get_system_guid_rsp rsp;
if (uuid == NULL) {
printk(BIOS_ERR, "%s failed, null pointer parameter\n",
__func__);
return CB_ERR;
}
ret = ipmi_kcs_message(port, IPMI_NETFN_APPLICATION, 0x0,
IPMI_BMC_GET_SYSTEM_GUID, NULL, 0,
(unsigned char *) &rsp, sizeof(rsp));
if (ret < sizeof(struct ipmi_rsp) || rsp.resp.completion_code) {
printk(BIOS_ERR, "IPMI: %s command failed (ret=%d resp=0x%x)\n",
__func__, ret, rsp.resp.completion_code);
return CB_ERR;
}
memcpy(uuid, rsp.data, 16);
return CB_SUCCESS;
}

View file

@ -21,6 +21,7 @@
#define IPMI_BMC_RESET_WDG_TIMER 0x22
#define IPMI_BMC_SET_WDG_TIMER 0x24
#define IPMI_BMC_GET_WDG_TIMER 0x25
#define IPMI_BMC_GET_SYSTEM_GUID 0x37
/* BMC watchdog timeout action */
enum ipmi_bmc_timeout_action_type {
@ -44,6 +45,74 @@ struct ipmi_wdt_rsp {
uint16_t present_countdown_val;
} __packed;
struct ipmi_get_system_guid_rsp {
struct ipmi_rsp resp;
uint8_t data[16];
} __packed;
struct ipmi_read_fru_data_req {
uint8_t fru_device_id;
uint16_t fru_offset;
uint8_t count; /* count to read, 1-based. */
} __packed;
struct ipmi_read_fru_data_rsp {
struct ipmi_rsp resp;
uint8_t count; /* count returned, 1-based. */
uint8_t data[CONFIG_IPMI_FRU_SINGLE_RW_SZ];
} __packed;
/* Platform Management FRU Information Storage Definition Spec. */
#define PRODUCT_MAN_TYPE_LEN_OFFSET 3
#define BOARD_MAN_TYPE_LEN_OFFSET 6
struct ipmi_fru_common_hdr {
uint8_t format_version;
uint8_t internal_use_area_offset;
uint8_t chassis_area_offset;
uint8_t board_area_offset;
uint8_t product_area_offset;
uint8_t multirecord_area_offset;
uint8_t pad;
uint8_t checksum;
} __packed;
/* The fru_xxx_info only declares the strings that may be added to SMBIOS. */
struct fru_product_info {
char *manufacturer;
char *product_name;
char *product_partnumber;
char *product_version;
char *serial_number;
char *asset_tag;
};
struct fru_board_info {
char *manufacturer;
char *product_name;
char *serial_number;
char *part_number;
};
struct fru_info_str {
struct fru_product_info prod_info;
struct fru_board_info board_info;
};
enum typecode {
BINARY = 0,
BCD_PLUS = 1,
ASCII_6BIT = 2,
ASCII_8BIT = 3,
};
enum fru_area {
INTERNAL_USE_AREA = 0,
CHASSIS_INFO_AREA = 1,
BOARD_INFO_AREA = 2,
PRODUCT_INFO_AREA = 3,
MULTIRECORD_INFO_AREA = 4,
};
/*
* Initialize and start BMC FRB2 watchdog timer with the
* provided timer countdown and action values.
@ -54,4 +123,16 @@ enum cb_err ipmi_init_and_start_bmc_wdt(const int port, uint16_t countdown,
/* Returns CB_SUCCESS on success and CB_ERR if an error occurred */
enum cb_err ipmi_stop_bmc_wdt(const int port);
/* IPMI get BMC system GUID and store it to parameter uuid.
* Returns CB_SUCCESS on success and CB_ERR if an error occurred */
enum cb_err ipmi_get_system_guid(const int port, uint8_t *uuid);
/* Read all FRU inventory areas string data into fru_info_str with
* the same FRU device id. */
void read_fru_areas(const int port, uint8_t id, uint16_t offset,
struct fru_info_str *fru_info_str);
/* Read a particular FRU inventory area into fru_info_str. */
void read_fru_one_area(const int port, uint8_t id, uint16_t offset,
struct fru_info_str *fru_info_str, enum fru_area fru_area);
#endif

View file

@ -64,11 +64,6 @@ asmlinkage void console_init(void);
int console_log_level(int msg_level);
void do_putchar(unsigned char byte);
/* Return number of microseconds elapsed from start of stage or the previous
get_and_reset() call. */
long console_time_get_and_reset(void);
void console_time_report(void);
#define printk(LEVEL, fmt, args...) do_printk(LEVEL, fmt, ##args)
#define vprintk(LEVEL, fmt, args) do_vprintk(LEVEL, fmt, args)
@ -92,8 +87,6 @@ static inline int console_log_level(int msg_level) { return 0; }
static inline void printk(int LEVEL, const char *fmt, ...) {}
static inline void vprintk(int LEVEL, const char *fmt, va_list args) {}
static inline void do_putchar(unsigned char byte) {}
static inline long console_time_get_and_reset(void) { return 0; }
static inline void console_time_report(void) {}
#endif
int do_printk(int msg_level, const char *fmt, ...)

View file

@ -16,6 +16,7 @@
/* Page attribute type MSR */
#define TSC_MSR 0x10
#define IA32_PLATFORM_ID 0x17
#define IA32_APIC_BASE_MSR_INDEX 0x1B
#define IA32_FEATURE_CONTROL 0x3a
#define FEATURE_CONTROL_LOCK_BIT (1 << 0)
#define FEATURE_ENABLE_VMX (1 << 2)
@ -30,6 +31,10 @@
#define IA32_BIOS_SIGN_ID 0x8b
#define IA32_MPERF 0xe7
#define IA32_APERF 0xe8
/* STM */
#define IA32_SMM_MONITOR_CTL_MSR 0x9B
#define SMBASE_RO_MSR 0x98
#define IA32_SMM_MONITOR_VALID (1 << 0)
#define IA32_MCG_CAP 0x179
#define MCG_CTL_P (1 << 3)
#define MCA_BANKS_MASK 0xff
@ -45,6 +50,9 @@
#define ENERGY_POLICY_POWERSAVE 15
#define IA32_PACKAGE_THERM_INTERRUPT 0x1b2
#define IA32_PLATFORM_DCA_CAP 0x1f8
#define SMRR_PHYSBASE_MSR 0x1F2
#define SMRR_PHYSMASK_MSR 0x1F3
#define IA32_PLATFORM_DCA_CAP 0x1f8
#define IA32_PAT 0x277
#define IA32_MC0_CTL 0x400
#define IA32_MC0_STATUS 0x401
@ -65,6 +73,9 @@
#define MCA_STATUS_LO_ERRCODE_EXT_SH 16
#define MCA_STATUS_LO_ERRCODE_EXT_MASK (0x3f << MCA_STATUS_LO_ERRCODE_EXT_SH)
#define MCA_STATUS_LO_ERRCODE_MASK (0xffff << 0)
#define IA32_VMX_BASIC_MSR 0x480
#define VMX_BASIC_HI_DUAL_MONITOR (1UL << (49 - 32))
#define IA32_VMX_MISC_MSR 0x485
#define MC0_ADDR 0x402
#define MC0_MISC 0x403
#define MC0_CTL_MASK 0xC0010044

View file

@ -63,7 +63,11 @@ extern unsigned char _binary_smm_end[];
struct smm_runtime {
u32 smbase;
u32 smm_size;
u32 save_state_size;
u32 num_cpus;
/* STM's 32bit entry into SMI handler */
u32 start32_offset;
/* The apic_id_to_cpu provides a mapping from APIC id to CPU number.
* The CPU number is indicated by the index into the array by matching
* the default APIC id and value at the index. The stub loader
@ -114,6 +118,12 @@ void *smm_get_save_state(int cpu);
* 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;
@ -127,12 +137,24 @@ struct smm_loader_params {
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)
u32 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);
@ -146,6 +168,8 @@ void smm_region(uintptr_t *start, size_t *size);
enum {
/* SMM handler area. */
SMM_SUBREGION_HANDLER,
/* MSEG (STM). */
SMM_SUBREGION_MSEG,
/* SMM cache region. */
SMM_SUBREGION_CACHE,
/* Chipset specific area. */

View file

@ -63,7 +63,6 @@ static boot_state_t bs_payload_boot(void *arg);
struct boot_state_times {
int num_samples;
struct mono_time samples[MAX_TIME_SAMPLES];
long console_usecs[MAX_TIME_SAMPLES];
};
/* The prologue (BS_ON_ENTRY) and epilogue (BS_ON_EXIT) of a state can be
@ -242,9 +241,6 @@ static void bs_sample_time(struct boot_state *state)
{
struct mono_time *mt;
long console_usecs = console_time_get_and_reset();
state->times.console_usecs[state->times.num_samples] = console_usecs;
mt = &state->times.samples[state->times.num_samples];
timer_monotonic_get(mt);
state->times.num_samples++;
@ -261,10 +257,6 @@ static void bs_report_time(struct boot_state *state)
run_time = mono_time_diff_microseconds(&samples[1], &samples[2]);
exit_time = mono_time_diff_microseconds(&samples[2], &samples[3]);
entry_time -= state->times.console_usecs[1];
run_time -= state->times.console_usecs[2];
exit_time -= state->times.console_usecs[3];
/* Report with millisecond precision to reduce log diffs. */
entry_time = DIV_ROUND_CLOSEST(entry_time, USECS_PER_MSEC);
run_time = DIV_ROUND_CLOSEST(run_time, USECS_PER_MSEC);

View file

@ -70,8 +70,6 @@ void run_romstage(void)
timestamp_add_now(TS_END_COPYROM);
console_time_report();
prog_run(&romstage);
fail:
@ -155,8 +153,6 @@ void run_ramstage(void)
timestamp_add_now(TS_END_COPYRAM);
console_time_report();
/* This overrides the arg fetched from the relocatable module */
prog_set_arg(&ramstage, cbmem_top());

View file

@ -1,17 +1,4 @@
if BOARD_FACEBOOK_WATSON
config BOARD_SPECIFIC_OPTIONS
def_bool y
select SOC_INTEL_FSP_BROADWELL_DE
select BOARD_ROMSIZE_KB_16384
select HAVE_ACPI_TABLES
select HAVE_OPTION_TABLE
select INTEGRATED_UART
select SERIRQ_CONTINUOUS_MODE
select MAINBOARD_USES_IFD_GBE_REGION
select MAINBOARD_HAS_LPC_TPM
select MAINBOARD_HAS_TPM1
select NO_UART_ON_SUPERIO
if BOARD_FACEBOOK_WATSON || BOARD_FACEBOOK_WATSON_V2
config VBOOT
select VBOOT_VBNV_CMOS
@ -21,6 +8,27 @@ config VBOOT
select GBB_FLAG_DISABLE_EC_SOFTWARE_SYNC
select GBB_FLAG_DISABLE_FWMP
config BOARD_SPECIFIC_OPTIONS
def_bool y
select SOC_INTEL_FSP_BROADWELL_DE
select BOARD_ROMSIZE_KB_16384
select GENERATE_SMBIOS_TABLES
select HAVE_ACPI_TABLES
select HAVE_OPTION_TABLE
select INTEGRATED_UART
select IPMI_KCS if BOARD_FACEBOOK_WATSON_V2
select SERIRQ_CONTINUOUS_MODE
select MAINBOARD_USES_IFD_GBE_REGION
select MAINBOARD_HAS_LPC_TPM
select MAINBOARD_HAS_TPM1 if BOARD_FACEBOOK_WATSON
select MAINBOARD_HAS_TPM2 if BOARD_FACEBOOK_WATSON_V2
select NO_UART_ON_SUPERIO
select VBOOT if BOARD_FACEBOOK_WATSON_V2
select VBOOT_MEASURED_BOOT if BOARD_FACEBOOK_WATSON_V2
select VBOOT_STARTS_IN_ROMSTAGE if BOARD_FACEBOOK_WATSON_V2
select VPD
select VPD_SMBIOS_VERSION
config MAINBOARD_DIR
string
default "facebook/watson"
@ -29,6 +37,10 @@ config MAINBOARD_PART_NUMBER
string
default "Watson"
config DEVICETREE
string
default "variants/$(CONFIG_VARIANT_DIR)/devicetree.cb"
config IRQ_SLOT_COUNT
int
default 18
@ -37,6 +49,60 @@ config CBFS_SIZE
hex
default 0x00800000
config VARIANT_DIR
string
default "watson" if BOARD_FACEBOOK_WATSON
default "watson_v2" if BOARD_FACEBOOK_WATSON_V2
config VBOOT_FWID_MODEL
string
default "$(CONFIG_MAINBOARD_VENDOR)_$(CONFIG_MAINBOARD_PART_NUMBER)"
config VBOOT_FIRMWARE_PRIVKEY
string
depends on BOARD_FACEBOOK_WATSON_V2
default "$(VBOOT_SOURCE)/tests/devkeys/firmware_data_key.vbprivk"
config VBOOT_FWID_VERSION
string
depends on BOARD_FACEBOOK_WATSON_V2
default ".$(KERNELVERSION)"
config VBOOT_KERNEL_KEY
string
depends on BOARD_FACEBOOK_WATSON_V2
default "$(VBOOT_SOURCE)/tests/devkeys/kernel_subkey.vbpubk"
config VBOOT_KEYBLOCK
string
depends on BOARD_FACEBOOK_WATSON_V2
default "$(VBOOT_SOURCE)/tests/devkeys/firmware.keyblock"
config VBOOT_KEYBLOCK_VERSION
int
depends on BOARD_FACEBOOK_WATSON_V2
default 1
config VBOOT_KEYBLOCK_PREAMBLE_FLAGS
hex
depends on BOARD_FACEBOOK_WATSON_V2
default 0x0
config VBOOT_RECOVERY_KEY
string
depends on BOARD_FACEBOOK_WATSON_V2
default "$(VBOOT_SOURCE)/tests/devkeys/recovery_key.vbpubk"
config VBOOT_ROOT_KEY
string
depends on BOARD_FACEBOOK_WATSON_V2
default "$(VBOOT_SOURCE)/tests/devkeys/root_key.vbpubk"
config VBOOT_VBNV_OFFSET
hex
depends on BOARD_FACEBOOK_WATSON_V2
default 0x26
config VIRTUAL_ROM_SIZE
hex
# Set to CONFIG_ROM_SIZE*2 if using concatenated flash chips.
@ -48,10 +114,11 @@ config DRIVERS_UART_8250IO
config FMDFILE
string
default "src/mainboard/$(CONFIG_MAINBOARD_DIR)/board.fmd"
default "src/mainboard/$(CONFIG_MAINBOARD_DIR)/board.fmd" if BOARD_FACEBOOK_WATSON
default "src/mainboard/$(CONFIG_MAINBOARD_DIR)/vboot-ro.fmd" if BOARD_FACEBOOK_WATSON_V2
config ENABLE_TURBO
bool "Enable turbo frequency"
default n
endif # BOARD_FACEBOOK_WATSON
endif # BOARD_FACEBOOK_WATSON*

View file

@ -1,2 +1,5 @@
config BOARD_FACEBOOK_WATSON
bool "Watson"
bool "Watson_v1"
config BOARD_FACEBOOK_WATSON_V2
bool "Watson_v2"

View file

@ -14,3 +14,6 @@
##
ramstage-y += irqroute.c
subdirs-y += variants/$(VARIANT_DIR)
CPPFLAGS_common += -I$(src)/mainboard/$(MAINBOARDDIR)/include

View file

@ -9,8 +9,8 @@ FLASH@0xff000000 0x1000000 {
FMAP@0x0 0x1000
RW_MISC@0x1000 0xe000 {
RW_ELOG@0x0 0x4000
RW_VPD@0x4000 0x2000
RW_MISC_UNUSED@0x6000 0x5000
RW_VPD@0x4000 0x4000
RW_MISC_UNUSED@0x8000 0x4000
RW_NVRAM@0xc000 0x2000
}
UNIFIED_MRC_CACHE@0x10000 0x20000 {
@ -19,8 +19,7 @@ FLASH@0xff000000 0x1000000 {
}
# This only exists to satisfy tools that specifically
# look for RO_VPD.
RO_VPD@0x30000 0x1000
UNUSED_4@0x31000 0x1cf000
COREBOOT(CBFS)@0x200000 0x800000
RO_VPD@0x30000 0x4000
COREBOOT(CBFS)@0x34000
}
}

View file

@ -0,0 +1,26 @@
/*
* This file is part of the coreboot project.
*
* Copyright (C) 2007-2009 coresystems GmbH
* Copyright (C) 2011 Google Inc.
* Copyright (C) Facebook, Inc. and its affiliates
*
* 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 BASEBOARD_VARIANTS_H
#define BASEBOARD_VARIANTS_H
#include <soc/romstage.h>
void variant_romstage_fsp_init_params(UPD_DATA_REGION *UpdData);
void variant_early_mainboard_romstage_entry(void);
#endif /* BASEBOARD_VARIANTS_H */

View file

@ -17,6 +17,7 @@
#include <stddef.h>
#include <soc/romstage.h>
#include <drivers/intel/fsp1_0/fsp_util.h>
#include <variants.h>
/**
* /brief mainboard call for setup that needs to be done before fsp init
@ -24,7 +25,7 @@
*/
void early_mainboard_romstage_entry(void)
{
variant_early_mainboard_romstage_entry();
}
/**
@ -40,6 +41,19 @@ void late_mainboard_romstage_entry(void)
* /brief customize fsp parameters here if needed
*/
void romstage_fsp_rt_buffer_callback(FSP_INIT_RT_BUFFER *FspRtBuffer)
{
UPD_DATA_REGION *UpdData = FspRtBuffer->Common.UpdDataRgnPtr;
/* Variant-specific memory params */
variant_romstage_fsp_init_params(UpdData);
}
__weak void variant_romstage_fsp_init_params(UPD_DATA_REGION *UpdData)
{
}
__weak void variant_early_mainboard_romstage_entry(void)
{
}

View file

@ -0,0 +1 @@
romstage-y += romstage.c

View file

@ -0,0 +1,24 @@
chip soc/intel/fsp_broadwell_de
register "lpc_lgmr" = "0xb0000001" # CPLD
device cpu_cluster 0 on
device lapic 0 on end
end
device domain 0 on
device pci 00.0 on end # SoC router
device pci 14.0 on end # xHCI Controller
device pci 19.0 on end # Gigabit LAN Controller
device pci 1d.0 on end # EHCI Controller
device pci 1f.0 on # LPC Bridge
chip drivers/pc80/tpm
device pnp 0c31.0 on end
end
chip drivers/ipmi
device pnp ca2.0 on end
register "bmc_i2c_address" = "0x20"
end
end
device pci 1f.2 on end # SATA Controller
device pci 1f.3 on end # SMBus Controller
device pci 1f.5 on end # SATA Controller
end
end

View file

@ -0,0 +1,60 @@
/*
* This file is part of the coreboot project.
*
* Copyright (C) 2007-2009 coresystems GmbH
* Copyright (C) 2011 Google Inc.
* Copyright (C) Facebook, Inc. and its affiliates
*
* 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 <device/pci_ops.h>
#include <soc/lpc.h>
#include <soc/pci_devs.h>
#include <soc/romstage.h>
#include <variants.h>
void variant_romstage_fsp_init_params(UPD_DATA_REGION *UpdData)
{
/* Configure IOU1 as 4*4 lanes */
UpdData->ConfigIOU1_PciPort3 = 0;
/* Configure IOU2 as 2*4 lanes */
UpdData->ConfigIOU2_PciPort1 = 0;
/* Configure PCH PCIe ports as 8*1 lanes */
UpdData->PchPciPort1 = 1;
UpdData->PchPciPort2 = 1;
UpdData->PchPciPort3 = 1;
UpdData->PchPciPort4 = 1;
UpdData->PchPciPort5 = 1;
UpdData->PchPciPort6 = 1;
UpdData->PchPciPort7 = 1;
UpdData->PchPciPort8 = 1;
/* Enable hotplug for PCH PCIe ports */
UpdData->HotPlug_PchPciPort1 = 1;
UpdData->HotPlug_PchPciPort2 = 1;
UpdData->HotPlug_PchPciPort3 = 1;
UpdData->HotPlug_PchPciPort4 = 1;
UpdData->HotPlug_PchPciPort5 = 1;
UpdData->HotPlug_PchPciPort6 = 1;
UpdData->HotPlug_PchPciPort7 = 1;
UpdData->HotPlug_PchPciPort8 = 1;
}
void variant_early_mainboard_romstage_entry(void)
{
// Enable LPC IO ports 0xca2, 0xca8 for IPMI
pci_write_config32(PCH_DEV_LPC, LPC_GEN2_DEC,
(0 << 16) | ALIGN_DOWN(0xca2, 4) | 1);
pci_write_config32(PCH_DEV_LPC, LPC_GEN3_DEC,
(0 << 16) | ALIGN_DOWN(0xca8, 4) | 1);
}

View file

@ -44,6 +44,7 @@ chip northbridge/intel/i945
register "has_bdc_detection" = "1"
register "bdc_gpio_num" = "7"
register "bdc_gpio_lvl" = "0"
device pnp ff.2 on end
end
chip superio/nsc/pc87384
device pnp 2e.2 off # Serial Port / IR
@ -62,6 +63,7 @@ chip northbridge/intel/i945
register "regs" = "{ 0x2e, 0xf7, 0x3c,
0x20, 0x01, 0x00, 0x1b, 0x01,
0x54, 0xff, 0xff, 0x07 }"
device i2c 69 on end
end
end
end

View file

@ -57,6 +57,7 @@ chip northbridge/intel/i945
# vendor clockgen setup
register "regs" = "{ 0x6d, 0xff, 0xff,
0x20, 0x41, 0x7f, 0x18, 0x00 }"
device i2c 69 on end
end
end
end

View file

@ -9,7 +9,7 @@ config BOARD_SPECIFIC_OPTIONS
select INTEGRATED_UART if FSP_PACKAGE_DEFAULT
select HAVE_FSP_BIN if FSP_PACKAGE_DEFAULT
select SERIRQ_CONTINUOUS_MODE
select MAINBOARD_USES_IFD_GBE_REGION
select FSP_EHCI1_ENABLE
select MAINBOARD_HAS_LPC_TPM
select MAINBOARD_HAS_TPM1
select IPMI_KCS
@ -60,4 +60,6 @@ config FMDFILE
config IPMI_KCS_REGISTER_SPACING
default 4
config IPMI_FRU_SINGLE_RW_SZ
default 16
endif # BOARD_OCP_MONOLAKE

View file

@ -1,20 +0,0 @@
/*
* This file is part of the coreboot project.
*
* Copyright (C) 2012 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.
*/
Device (PWRB)
{
Name(_HID, EisaId("PNP0C0C"))
}

View file

@ -5,9 +5,7 @@ chip soc/intel/fsp_broadwell_de
device domain 0 on
device pci 00.0 on end # SoC router
device pci 02.2 off end # IOU0 port C, 10GbE
device pci 02.3 off end # IOU0 port D, 10GbE
device pci 14.0 on end # xHCI Controller
device pci 19.0 on end # Gigabit LAN Controller
device pci 1d.0 on end # EHCI Controller
device pci 1f.0 on
chip drivers/pc80/tpm
@ -16,10 +14,12 @@ chip soc/intel/fsp_broadwell_de
chip drivers/ipmi # BMC KCS
device pnp ca2.0 on end
register "bmc_i2c_address" = "0x20"
# On cold boot it takes a while for the BMC to start the IPMI service
register "wait_for_bmc" = "1"
register "bmc_boot_timeout" = "60"
end
end # LPC Bridge
device pci 1f.2 on end # SATA Controller
device pci 1f.3 on end # SMBus Controller
device pci 1f.5 on end # SATA Controller
end
end

View file

@ -38,257 +38,6 @@ DefinitionBlock(
#include <acpi/pcie1.asl>
}
Name (PRUN, Package() {
Package() { 0x0008FFFF, 0, \_SB.PCI0.LPC0.LNKA, 0 },
Package() { 0x0008FFFF, 1, \_SB.PCI0.LPC0.LNKB, 0 },
Package() { 0x0008FFFF, 2, \_SB.PCI0.LPC0.LNKC, 0 },
Package() { 0x0008FFFF, 3, \_SB.PCI0.LPC0.LNKD, 0 },
Package() { 0x0009FFFF, 0, \_SB.PCI0.LPC0.LNKA, 0 },
Package() { 0x0009FFFF, 1, \_SB.PCI0.LPC0.LNKB, 0 },
Package() { 0x0009FFFF, 2, \_SB.PCI0.LPC0.LNKC, 0 },
Package() { 0x0009FFFF, 3, \_SB.PCI0.LPC0.LNKD, 0 },
Package() { 0x000AFFFF, 0, \_SB.PCI0.LPC0.LNKA, 0 },
Package() { 0x000AFFFF, 1, \_SB.PCI0.LPC0.LNKB, 0 },
Package() { 0x000AFFFF, 2, \_SB.PCI0.LPC0.LNKC, 0 },
Package() { 0x000AFFFF, 3, \_SB.PCI0.LPC0.LNKD, 0 },
Package() { 0x000BFFFF, 0, \_SB.PCI0.LPC0.LNKA, 0 },
Package() { 0x000BFFFF, 1, \_SB.PCI0.LPC0.LNKB, 0 },
Package() { 0x000BFFFF, 2, \_SB.PCI0.LPC0.LNKC, 0 },
Package() { 0x000BFFFF, 3, \_SB.PCI0.LPC0.LNKD, 0 },
Package() { 0x000CFFFF, 0, \_SB.PCI0.LPC0.LNKA, 0 },
Package() { 0x000CFFFF, 1, \_SB.PCI0.LPC0.LNKB, 0 },
Package() { 0x000CFFFF, 2, \_SB.PCI0.LPC0.LNKC, 0 },
Package() { 0x000CFFFF, 3, \_SB.PCI0.LPC0.LNKD, 0 },
Package() { 0x000DFFFF, 0, \_SB.PCI0.LPC0.LNKA, 0 },
Package() { 0x000DFFFF, 1, \_SB.PCI0.LPC0.LNKB, 0 },
Package() { 0x000DFFFF, 2, \_SB.PCI0.LPC0.LNKC, 0 },
Package() { 0x000DFFFF, 3, \_SB.PCI0.LPC0.LNKD, 0 },
Package() { 0x000EFFFF, 0, \_SB.PCI0.LPC0.LNKA, 0 },
Package() { 0x000EFFFF, 1, \_SB.PCI0.LPC0.LNKB, 0 },
Package() { 0x000EFFFF, 2, \_SB.PCI0.LPC0.LNKC, 0 },
Package() { 0x000EFFFF, 3, \_SB.PCI0.LPC0.LNKD, 0 },
Package() { 0x000FFFFF, 0, \_SB.PCI0.LPC0.LNKA, 0 },
Package() { 0x000FFFFF, 1, \_SB.PCI0.LPC0.LNKB, 0 },
Package() { 0x000FFFFF, 2, \_SB.PCI0.LPC0.LNKC, 0 },
Package() { 0x000FFFFF, 3, \_SB.PCI0.LPC0.LNKD, 0 },
Package() { 0x0010FFFF, 0, \_SB.PCI0.LPC0.LNKA, 0 },
Package() { 0x0010FFFF, 1, \_SB.PCI0.LPC0.LNKB, 0 },
Package() { 0x0010FFFF, 2, \_SB.PCI0.LPC0.LNKC, 0 },
Package() { 0x0010FFFF, 3, \_SB.PCI0.LPC0.LNKD, 0 },
Package() { 0x0011FFFF, 0, \_SB.PCI0.LPC0.LNKA, 0 },
Package() { 0x0011FFFF, 1, \_SB.PCI0.LPC0.LNKB, 0 },
Package() { 0x0011FFFF, 2, \_SB.PCI0.LPC0.LNKC, 0 },
Package() { 0x0011FFFF, 3, \_SB.PCI0.LPC0.LNKD, 0 },
Package() { 0x0012FFFF, 0, \_SB.PCI0.LPC0.LNKA, 0 },
Package() { 0x0012FFFF, 1, \_SB.PCI0.LPC0.LNKB, 0 },
Package() { 0x0012FFFF, 2, \_SB.PCI0.LPC0.LNKC, 0 },
Package() { 0x0012FFFF, 3, \_SB.PCI0.LPC0.LNKD, 0 },
Package() { 0x0013FFFF, 0, \_SB.PCI0.LPC0.LNKA, 0 },
Package() { 0x0013FFFF, 1, \_SB.PCI0.LPC0.LNKB, 0 },
Package() { 0x0013FFFF, 2, \_SB.PCI0.LPC0.LNKC, 0 },
Package() { 0x0013FFFF, 3, \_SB.PCI0.LPC0.LNKD, 0 },
Package() { 0x0014FFFF, 0, \_SB.PCI0.LPC0.LNKA, 0 },
Package() { 0x0014FFFF, 1, \_SB.PCI0.LPC0.LNKB, 0 },
Package() { 0x0014FFFF, 2, \_SB.PCI0.LPC0.LNKC, 0 },
Package() { 0x0014FFFF, 3, \_SB.PCI0.LPC0.LNKD, 0 },
Package() { 0x0016FFFF, 0, \_SB.PCI0.LPC0.LNKA, 0 },
Package() { 0x0016FFFF, 1, \_SB.PCI0.LPC0.LNKB, 0 },
Package() { 0x0016FFFF, 2, \_SB.PCI0.LPC0.LNKC, 0 },
Package() { 0x0016FFFF, 3, \_SB.PCI0.LPC0.LNKD, 0 },
Package() { 0x0017FFFF, 0, \_SB.PCI0.LPC0.LNKA, 0 },
Package() { 0x0017FFFF, 1, \_SB.PCI0.LPC0.LNKB, 0 },
Package() { 0x0017FFFF, 2, \_SB.PCI0.LPC0.LNKC, 0 },
Package() { 0x0017FFFF, 3, \_SB.PCI0.LPC0.LNKD, 0 },
Package() { 0x0018FFFF, 0, \_SB.PCI0.LPC0.LNKA, 0 },
Package() { 0x0018FFFF, 1, \_SB.PCI0.LPC0.LNKB, 0 },
Package() { 0x0018FFFF, 2, \_SB.PCI0.LPC0.LNKC, 0 },
Package() { 0x0018FFFF, 3, \_SB.PCI0.LPC0.LNKD, 0 },
Package() { 0x0019FFFF, 0, \_SB.PCI0.LPC0.LNKA, 0 },
Package() { 0x0019FFFF, 1, \_SB.PCI0.LPC0.LNKB, 0 },
Package() { 0x0019FFFF, 2, \_SB.PCI0.LPC0.LNKC, 0 },
Package() { 0x0019FFFF, 3, \_SB.PCI0.LPC0.LNKD, 0 },
Package() { 0x001CFFFF, 0, \_SB.PCI0.LPC0.LNKA, 0 },
Package() { 0x001CFFFF, 1, \_SB.PCI0.LPC0.LNKB, 0 },
Package() { 0x001CFFFF, 2, \_SB.PCI0.LPC0.LNKC, 0 },
Package() { 0x001CFFFF, 3, \_SB.PCI0.LPC0.LNKD, 0 },
Package() { 0x001DFFFF, 0, \_SB.PCI0.LPC0.LNKA, 0 },
Package() { 0x001DFFFF, 1, \_SB.PCI0.LPC0.LNKB, 0 },
Package() { 0x001DFFFF, 2, \_SB.PCI0.LPC0.LNKC, 0 },
Package() { 0x001DFFFF, 3, \_SB.PCI0.LPC0.LNKD, 0 },
Package() { 0x001EFFFF, 0, \_SB.PCI0.LPC0.LNKA, 0 },
Package() { 0x001EFFFF, 1, \_SB.PCI0.LPC0.LNKB, 0 },
Package() { 0x001EFFFF, 2, \_SB.PCI0.LPC0.LNKC, 0 },
Package() { 0x001EFFFF, 3, \_SB.PCI0.LPC0.LNKD, 0 },
Package() { 0x001FFFFF, 0, \_SB.PCI0.LPC0.LNKA, 0 },
Package() { 0x001FFFFF, 1, \_SB.PCI0.LPC0.LNKB, 0 },
Package() { 0x001FFFFF, 2, \_SB.PCI0.LPC0.LNKC, 0 },
Package() { 0x001FFFFF, 3, \_SB.PCI0.LPC0.LNKD, 0 },
})
Name (ARUN, Package() {
Package() { 0x0008FFFF, 0, 0, 16 },
Package() { 0x0008FFFF, 1, 0, 17 },
Package() { 0x0008FFFF, 2, 0, 18 },
Package() { 0x0008FFFF, 3, 0, 19 },
Package() { 0x0009FFFF, 0, 0, 16 },
Package() { 0x0009FFFF, 1, 0, 17 },
Package() { 0x0009FFFF, 2, 0, 18 },
Package() { 0x0009FFFF, 3, 0, 19 },
Package() { 0x000AFFFF, 0, 0, 16 },
Package() { 0x000AFFFF, 1, 0, 17 },
Package() { 0x000AFFFF, 2, 0, 18 },
Package() { 0x000AFFFF, 3, 0, 19 },
Package() { 0x000BFFFF, 0, 0, 16 },
Package() { 0x000BFFFF, 1, 0, 17 },
Package() { 0x000BFFFF, 2, 0, 18 },
Package() { 0x000BFFFF, 3, 0, 19 },
Package() { 0x000CFFFF, 0, 0, 16 },
Package() { 0x000CFFFF, 1, 0, 17 },
Package() { 0x000CFFFF, 2, 0, 18 },
Package() { 0x000CFFFF, 3, 0, 19 },
Package() { 0x000DFFFF, 0, 0, 16 },
Package() { 0x000DFFFF, 1, 0, 17 },
Package() { 0x000DFFFF, 2, 0, 18 },
Package() { 0x000DFFFF, 3, 0, 19 },
Package() { 0x000EFFFF, 0, 0, 16 },
Package() { 0x000EFFFF, 1, 0, 17 },
Package() { 0x000EFFFF, 2, 0, 18 },
Package() { 0x000EFFFF, 3, 0, 19 },
Package() { 0x000FFFFF, 0, 0, 16 },
Package() { 0x000FFFFF, 1, 0, 17 },
Package() { 0x000FFFFF, 2, 0, 18 },
Package() { 0x000FFFFF, 3, 0, 19 },
Package() { 0x0010FFFF, 0, 0, 16 },
Package() { 0x0010FFFF, 1, 0, 17 },
Package() { 0x0010FFFF, 2, 0, 18 },
Package() { 0x0010FFFF, 3, 0, 19 },
Package() { 0x0011FFFF, 0, 0, 16 },
Package() { 0x0011FFFF, 1, 0, 17 },
Package() { 0x0011FFFF, 2, 0, 18 },
Package() { 0x0011FFFF, 3, 0, 19 },
Package() { 0x0012FFFF, 0, 0, 16 },
Package() { 0x0012FFFF, 1, 0, 17 },
Package() { 0x0012FFFF, 2, 0, 18 },
Package() { 0x0012FFFF, 3, 0, 19 },
Package() { 0x0013FFFF, 0, 0, 16 },
Package() { 0x0013FFFF, 1, 0, 17 },
Package() { 0x0013FFFF, 2, 0, 18 },
Package() { 0x0013FFFF, 3, 0, 19 },
Package() { 0x0014FFFF, 0, 0, 16 },
Package() { 0x0014FFFF, 1, 0, 17 },
Package() { 0x0014FFFF, 2, 0, 18 },
Package() { 0x0014FFFF, 3, 0, 19 },
Package() { 0x0016FFFF, 0, 0, 16 },
Package() { 0x0016FFFF, 1, 0, 17 },
Package() { 0x0016FFFF, 2, 0, 18 },
Package() { 0x0016FFFF, 3, 0, 19 },
Package() { 0x0017FFFF, 0, 0, 16 },
Package() { 0x0017FFFF, 1, 0, 17 },
Package() { 0x0017FFFF, 2, 0, 18 },
Package() { 0x0017FFFF, 3, 0, 19 },
Package() { 0x0018FFFF, 0, 0, 16 },
Package() { 0x0018FFFF, 1, 0, 17 },
Package() { 0x0018FFFF, 2, 0, 18 },
Package() { 0x0018FFFF, 3, 0, 19 },
Package() { 0x0019FFFF, 0, 0, 16 },
Package() { 0x0019FFFF, 1, 0, 17 },
Package() { 0x0019FFFF, 2, 0, 18 },
Package() { 0x0019FFFF, 3, 0, 19 },
Package() { 0x001CFFFF, 0, 0, 16 },
Package() { 0x001CFFFF, 1, 0, 17 },
Package() { 0x001CFFFF, 2, 0, 18 },
Package() { 0x001CFFFF, 3, 0, 19 },
Package() { 0x001DFFFF, 0, 0, 16 },
Package() { 0x001DFFFF, 1, 0, 17 },
Package() { 0x001DFFFF, 2, 0, 18 },
Package() { 0x001DFFFF, 3, 0, 19 },
Package() { 0x001EFFFF, 0, 0, 16 },
Package() { 0x001EFFFF, 1, 0, 17 },
Package() { 0x001EFFFF, 2, 0, 18 },
Package() { 0x001EFFFF, 3, 0, 19 },
Package() { 0x001FFFFF, 0, 0, 16 },
Package() { 0x001FFFFF, 1, 0, 17 },
Package() { 0x001FFFFF, 2, 0, 18 },
Package() { 0x001FFFFF, 3, 0, 19 },
})
Device (UNC0)
{
Name (_HID, EisaId ("PNP0A03"))
Name (_UID, 0x3F)
Method (_BBN, 0, NotSerialized)
{
Return (0xff)
}
Name (_ADR, 0x00)
Method (_STA, 0, NotSerialized)
{
Return (0xf)
}
Name (_CRS, ResourceTemplate ()
{
WordBusNumber (ResourceProducer, MinFixed, MaxFixed, PosDecode,
0x0000, // Granularity
0x00FF, // Range Minimum
0x00FF, // Range Maximum
0x0000, // Translation Offset
0x0001, // Length
,, )
})
Method (_PRT, 0, NotSerialized)
{
If (LEqual (PICM, Zero))
{
Return (PRUN)
}
Return (ARUN)
}
}
#include <acpi/uncore.asl>
}
#include "acpi/mainboard.asl"
}

View file

@ -14,6 +14,7 @@
* GNU General Public License for more details.
*/
#include <bootstate.h>
#include <device/device.h>
#include <pc80/mc146818rtc.h>
#include <cf9_reset.h>
@ -22,6 +23,7 @@
#include <drivers/vpd/vpd.h>
#include <console/console.h>
#include <drivers/ipmi/ipmi_ops.h>
#include <gpio.h>
#include "ipmi.h"
/* VPD variable for enabling/disabling FRB2 timer. */
#define FRB2_TIMER "FRB2_TIMER"
@ -30,6 +32,10 @@
#define VPD_LEN 10
/* Default countdown is 15 minutes. */
#define DEFAULT_COUNTDOWN 9000
#define FRU_DEVICE_ID 0
static struct fru_info_str fru_strings;
#define MAX_IMC 1
#define MAX_DIMM_SIZE_GB (32 * MiB)
static void init_frb2_wdt(void)
{
@ -60,6 +66,44 @@ static void init_frb2_wdt(void)
}
}
#if CONFIG(GENERATE_SMBIOS_TABLES)
static int write_smbios_type16(struct device *dev, int *handle, unsigned long *current)
{
struct smbios_type16 *t = (struct smbios_type16 *)*current;
u32 maximum_capacity;
int len = sizeof(struct smbios_type16);
printk(BIOS_INFO, "Creating SMBIOS tables type 16 (note, ECC information is hard-coded) ...");
memset(t, 0, sizeof(struct smbios_type16));
t->type = SMBIOS_PHYS_MEMORY_ARRAY;
t->location = MEMORY_ARRAY_LOCATION_SYSTEM_BOARD;
t->use = MEMORY_ARRAY_USE_SYSTEM;
/* The ECC setting can`t be confirmed in FSP, so hardcode it. */
t->memory_error_correction = MEMORY_ARRAY_ECC_SINGLE_BIT;
t->memory_error_information_handle = 0xFFFE;
t->number_of_memory_devices = CONFIG_DIMM_MAX / MAX_IMC;
maximum_capacity = (u32)(CONFIG_DIMM_MAX * MAX_DIMM_SIZE_GB);
if (maximum_capacity >= 0x80000000) {
t->maximum_capacity = 0x80000000;
t->extended_maximum_capacity = maximum_capacity << 10;
} else {
t->maximum_capacity = (u32)maximum_capacity;
t->extended_maximum_capacity = 0;
}
*current += len;
t->handle = *handle;
*handle += 1;
t->length = len - 2;
printk(BIOS_INFO, "done\n");
return len;
}
#endif
/*
* mainboard_enable is executed as first thing after enumerate_buses().
* This is the earliest point to add customization.
@ -76,6 +120,12 @@ static void mainboard_enable(struct device *dev)
clear_ipmi_flags(&rsp);
system_reset();
}
read_fru_areas(BMC_KCS_BASE, FRU_DEVICE_ID, 0, &fru_strings);
#if (CONFIG(GENERATE_SMBIOS_TABLES))
dev->ops->get_smbios_data = write_smbios_type16;
#endif
}
struct chip_operations mainboard_ops = {
@ -95,3 +145,102 @@ void smbios_fill_dimm_locator(const struct dimm_info *dimm, struct smbios_type17
dimm->dimm_num);
t->bank_locator = smbios_add_string(t->eos, locator);
}
/* Override SMBIOS uuid from the value from BMC. */
void smbios_system_set_uuid(u8 *uuid)
{
ipmi_get_system_guid(BMC_KCS_BASE, uuid);
}
/* Override SMBIOS type 1 data. */
const char *smbios_system_manufacturer(void)
{
if (fru_strings.prod_info.manufacturer != NULL)
return (const char *)fru_strings.prod_info.manufacturer;
else
return CONFIG_MAINBOARD_SMBIOS_MANUFACTURER;
}
const char *smbios_system_product_name(void)
{
char *prod_name_partnumber;
/* Concatenates IPMI FRU Product Info product name
* and product part number. */
if (fru_strings.prod_info.product_name != NULL) {
if (fru_strings.prod_info.product_partnumber != NULL) {
/* Append a space after product_name. */
prod_name_partnumber = strconcat(fru_strings.prod_info.product_name,
" ");
if (!prod_name_partnumber)
return (const char *)fru_strings.prod_info.product_name;
prod_name_partnumber = strconcat(prod_name_partnumber,
fru_strings.prod_info.product_partnumber);
if (!prod_name_partnumber)
return (const char *)fru_strings.prod_info.product_name;
return (const char *)prod_name_partnumber;
} else {
return (const char *)fru_strings.prod_info.product_name;
}
} else {
return CONFIG_MAINBOARD_SMBIOS_PRODUCT_NAME;
}
}
const char *smbios_system_serial_number(void)
{
if (fru_strings.prod_info.serial_number != NULL)
return (const char *)fru_strings.prod_info.serial_number;
else
return CONFIG_MAINBOARD_SERIAL_NUMBER;
}
const char *smbios_system_version(void)
{
if (fru_strings.prod_info.product_version != NULL)
return (const char *)fru_strings.prod_info.product_version;
else
return CONFIG_MAINBOARD_SERIAL_NUMBER;
}
/* Override SMBIOS type 2 data. */
const char *smbios_mainboard_version(void)
{
if (fru_strings.board_info.part_number != NULL)
return (const char *)fru_strings.board_info.part_number;
else
return CONFIG_MAINBOARD_VERSION;
}
const char *smbios_mainboard_manufacturer(void)
{
if (fru_strings.board_info.manufacturer != NULL)
return (const char *)fru_strings.board_info.manufacturer;
else
return CONFIG_MAINBOARD_SMBIOS_MANUFACTURER;
}
const char *smbios_mainboard_product_name(void)
{
if (fru_strings.board_info.product_name != NULL)
return (const char *)fru_strings.board_info.product_name;
else
return CONFIG_MAINBOARD_SMBIOS_PRODUCT_NAME;
}
const char *smbios_mainboard_serial_number(void)
{
if (fru_strings.board_info.serial_number != NULL)
return (const char *)fru_strings.board_info.serial_number;
else
return CONFIG_MAINBOARD_SERIAL_NUMBER;
}
/* Set the BMC BIOS POST complete GPIO (FM_BIOS_POST_CMPLT_N) on payload load. */
static void bmc_set_post_complete_gpio_callback(void *arg)
{
/* GPIO 46 FM_BIOS_POST_CMPLT_N */
gpio_set(46, 0);
printk(BIOS_DEBUG, "BMC: POST complete gpio set\n");
}
BOOT_STATE_INIT_ENTRY(BS_PAYLOAD_BOOT, BS_ON_ENTRY, bmc_set_post_complete_gpio_callback, NULL);

View file

@ -19,9 +19,6 @@
#include <soc/romstage.h>
#include <drivers/intel/fsp1_0/fsp_util.h>
#include <drivers/vpd/vpd.h>
#include <cpu/x86/msr.h>
#include <cf9_reset.h>
#include <console/console.h>
#include <device/pci_ops.h>
#include <soc/pci_devs.h>
#include <soc/lpc.h>
@ -193,20 +190,7 @@ static const struct gpio_config gpio_tables[] = {
*/
void early_mainboard_romstage_entry(void)
{
/*
* Sometimes the system boots in an invalid state, where random values
* have been written to MSRs and then the MSRs are locked.
* Seems to always happen on warm reset.
*
* Power cycling or a board_reset() isn't sufficient in this case, so
* issue a full_reset() to "fix" this issue.
*/
msr_t msr = rdmsr(IA32_FEATURE_CONTROL);
if (msr.lo & 1) {
console_init();
printk(BIOS_EMERG, "Detected broken platform state. Issuing full reset\n");
full_reset();
}
}
/**

View file

@ -17,9 +17,6 @@
#include <stddef.h>
#include <soc/romstage.h>
#include <drivers/intel/fsp1_0/fsp_util.h>
#include <cpu/x86/msr.h>
#include <cf9_reset.h>
#include <console/console.h>
#include <device/pci_ops.h>
#include <soc/pci_devs.h>
#include <soc/lpc.h>
@ -44,25 +41,6 @@ void early_mainboard_romstage_entry(void)
if (CONFIG(CONSOLE_SERIAL))
ite_enable_serial(SERIAL_DEV, CONFIG_TTYS0_BASE);
/*
* Sometimes the system boots in an invalid state, where random values
* have been written to MSRs and then the MSRs are locked.
* Seems to always happen on warm reset.
*
* Power cycling or a board_reset() isn't sufficient in this case, so
* issue a full_reset() to "fix" this issue.
*
* It seems to be a deficiency in the reset logic, as other
* FSP broadwell DE boards are not affected.
*/
msr_t msr = rdmsr(IA32_FEATURE_CONTROL);
if (msr.lo & 1) {
console_init();
printk(BIOS_EMERG, "Detected broken platform state. Issuing full reset\n");
full_reset();
}
}
/**

View file

@ -261,7 +261,6 @@ DefinitionBlock(
Return (0xff)
}
Name (_ADR, 0x00)
Method (_STA, 0, NotSerialized)
{
Return (0xf)

View file

@ -14,3 +14,4 @@
##
source "src/security/intel/txt/Kconfig"
source "src/security/intel/stm/Kconfig"

View file

@ -1 +1,2 @@
subdirs-y += txt
subdirs-y += stm

View file

@ -0,0 +1,122 @@
config STM
bool "Enable STM"
default n
depends on SMM_TSEG
select USE_BLOBS
help
Enabling the STM will load a simple hypervisor into SMM that will
restrict the actions of the SMI handler, which is the part of BIOS
that functions in system management mode (SMM). The kernel can
configure the STM to prevent the SMI handler from accessing platform
resources.
The STM closes a vulnerability in Intel TXT (D-RTM)
The SMI handler provides a list of platform resources that it
requires access to the STM during STM startup, which the kernel
cannot override.
An additional capability, called STM-PE, provides a protected
execution capability that allows modules to be executed without
observation and interference. Examples of usage include kernel
introspection and virtualized trusted platform module (vTPM).
Requirement: SMM must be enabled and there must be sufficient room
within the TSEG to fit the MSEG.
if STM
menu "SMI Transfer Monitor (STM)"
config MSEG_SIZE
hex "mseg size"
default 0x100000
help
The MSEG_SIZE of 0x100000 assumes that:
IED_REGION_SIZE = 0x400000
SMM_RESERVED_SIZE = 0x200000
SMM_TSEG_SIZE = 0x800000
To use STM/PE, a larger MSEG_SIZE is necessary. This can be
done by either increasing SMM_TSEG_SIZE or reducing the
IED_REGION_SIZE and/or SMM_RESERVED_SIZE or some combination
of the three.
NOTE: The authors experience is that these configuration
parameters have to be changed at the soc Konfig for them to
be applied.
Minimum sizes:
STM only - 0x100000 - Supports up to 38 processor threads
- 0x200000 - Supports up to 102 processor threads
STM/PE - 0x300000+ depending on the amount of memory needed
for the protected execution virtual
machine (VM/PE)
config STM_STMPE_ENABLED
bool "STM/PE Enabled"
default n
help
STM/PE provides for additional virtual machines in SMRAM
that provides a protected execution environment for
applications such as introspection, which need to be
protected from malicious code. More information can be
found on the stmpe branch of
https://review.coreboot.org/STM
config BIOS_RESOURCE_LIST_SIZE
hex "bios resource list size"
default 0x1000
help
The BIOS resource list defines the resources that the
SMI handler needs. This list is created during the
coreboot bootup. Unless there has been a lot of elements
added to this list, this value should not change.
config STM_BINARY_FILE
string "STM binary file"
default "3rdparty/stm/Stm/build/StmPkg/Core/stm.bin"
help
Location of the STM binary file. The default location is
where the file will be located when coreboot builds
the STM.
config STM_HEAPSIZE
hex "stm heapsize"
default 0x46000
help
The STM_HEAPSIZE defines the heap space that is available
to the STM. The default size assumes a MSEG_SIZE of 0x100000.
For STM/PE this size should be a minimum of 0x246000.
config STM_TTYS0_BASE
hex "stm uart"
default TTYS0_BASE if TTYS0_BASE
default 0x000
help
Defines the serial port for STM console output. 0x000 indicates
no serial port.
config STM_CBMEM_CONSOLE
bool "STM cbmem console"
default n
depends on CONSOLE_CBMEM
help
Places the STM console output into the cbmem.
choice
prompt "Select STM console output"
config STM_CONSOLE_DEBUG
bool "Debug output"
depends on STM_CBMEM_CONSOLE || STM_TTYS0_BASE
help
"Produces all STM console output"
config STM_CONSOLE_RELEASE
bool "Deactivate console output"
help
"No console output is produced"
endchoice
endmenu #STM
endif

View file

@ -0,0 +1,33 @@
# SPDX-License-Identifier: BSD-2-Clause
project_name=STM
project_dir=../../../../3rdparty/stm/
build_dir=$(project_dir)/Stm/build
project_git_branch=$(CONFIG_STM_GIT_BRANCH)
ifeq ($(CONFIG_STM_CONSOLE_DEBUG),y)
STM_BUILD="debug"
endif
ifeq ($(CONFIG_STM_CONSOLE_RELEASE),y)
STM_BUILD="release"
endif
all: build
build:
echo "STM - Build"
cd $(project_dir)/Stm; \
mkdir -p build; \
cd build; \
cmake .. -DBIOS=coreboot \
-DUART=$(CONFIG_STM_TTYS0_BASE) \
-DHEAPSIZE=$(CONFIG_STM_HEAPSIZE) \
-DCBMEM_ENABLE=$(CONFIG_STM_CBMEM_CONSOLE) \
-DSTMPE_ENABLED=$(CONFIG_STM_STMPE_ENABLED) \
-DBUILD=$(STM_BUILD); \
$(MAKE);
.PHONY: build

View file

@ -0,0 +1,20 @@
# put the stm where it can be found
cbfs-files-$(CONFIG_STM) += stm.bin
stm.bin-file := $(CONFIG_STM_BINARY_FILE)
stm.bin-type := raw
ramstage-$(CONFIG_STM) += SmmStm.c
ramstage-$(CONFIG_STM) += StmPlatformSmm.c
ramstage-$(CONFIG_STM) += StmPlatformResource.c
3rdparty/stm/Stm/build/StmPkg/Core/stm.bin: $(obj)/config.h
$(MAKE) -C src/security/intel/stm \
CONFIG_STM_TTYS0_BASE=$(CONFIG_STM_TTYS0_BASE) \
CONFIG_STM_HEAPSIZE=$(CONFIG_STM_HEAPSIZE) \
CONFIG_STM_CONSOLE_DEBUG=$(CONFIG_STM_CONSOLE_DEBUG) \
CONFIG_STM_CONSOLE_RELEASE=$(CONFIG_STM_CONSOLE_RELEASE) \
CONFIG_STM_GIT_BRANCH=$(CONFIG_STM_GIT_BRANCH) \
CONFIG_STM_STMPE_ENABLED=$(CONFIG_STM_STMPE_ENABLED) \
CONFIG_STM_CBMEM_CONSOLE=$(CONFIG_STM_CBMEM_CONSOLE)

View file

@ -0,0 +1,657 @@
/* @file
* SMM STM support
*
* Copyright (c) 2015 - 2016, Intel Corporation. All rights reserved.
*
* This program and the accompanying materials are licensed and made available
* under the terms and conditions of the BSD License which accompanies this
* distribution. The full text of the license may be found at
* http://opensource.org/licenses/bsd-license.php.
*
* THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
* WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR
* IMPLIED.
*
*/
#include <console/console.h>
#include <cpu/x86/cr.h>
#include <cpu/x86/mp.h>
#include <cpu/x86/msr.h>
#include <cpu/x86/cache.h>
#include <security/intel/stm/SmmStm.h>
#include <string.h>
#define TXT_EVTYPE_BASE 0x400
#define TXT_EVTYPE_STM_HASH (TXT_EVTYPE_BASE + 14)
#define RDWR_ACCS 3
#define FULL_ACCS 7
#define SIZE_4KB 0x00001000
#define SIZE_4MB 0x00400000
#define PTP_SIZE SIZE_4KB
#define IA32_PG_P (1 << 0)
#define IA32_PG_RW (1 << 1)
#define IA32_PG_PS (1 << 7)
#define STM_PAGE_SHIFT 12
#define STM_PAGE_MASK 0xFFF
#define STM_SIZE_TO_PAGES(a) (((a) >> STM_PAGE_SHIFT) + (((a)&STM_PAGE_MASK) ? 1 : 0))
#define STM_PAGES_TO_SIZE(a) ((a) << STM_PAGE_SHIFT)
#define STM_ACCESS_DENIED 15
#define STM_UNSUPPORTED 3
#define STM_BUFFER_TOO_SMALL 1
#define STM_SM_MONITOR_STATE_ENABLED 1
typedef struct {
uint64_t vmcs_revision_id : 31;
uint64_t always_zero : 1;
uint64_t vmcs_size : 13;
uint64_t reserved1 : 3;
uint64_t vmxon_add_width : 1;
uint64_t stm_supported : 1;
uint64_t vmcs_memory_type : 4;
uint64_t in_out_reporting : 1;
uint64_t may_clear_defaults : 1;
uint64_t reserved2 : 8;
} VMX_BASIC_MSR_BITS;
typedef union {
VMX_BASIC_MSR_BITS bits;
uint64_t uint64;
msr_t msr;
} VMX_BASIC_MSR;
typedef struct {
uint64_t valid : 1;
uint64_t reserved1 : 1;
uint64_t vmx_off_blockSmi : 1;
uint64_t reserved2 : 9;
uint64_t mseg_address : 20;
uint64_t reserved3 : 32;
} SMM_MONITOR_CTL_MSR_BITS;
extern struct mp_state {
struct mp_ops ops;
int cpu_count;
uintptr_t perm_smbase;
size_t perm_smsize;
size_t smm_save_state_size;
int do_smm;
} mp_state;
typedef union {
SMM_MONITOR_CTL_MSR_BITS bits;
uint64_t uint64;
msr_t msr;
} SMM_MONITOR_CTL_MSR;
// Template of STM_RSC_END structure for copying.
STM_RSC_END m_rsc_end_node = {
{END_OF_RESOURCES, sizeof(STM_RSC_END)},
};
uint8_t *m_stm_resources_ptr = NULL;
uint32_t m_stm_resource_total_size = 0x0;
uint32_t m_stm_resource_size_used = 0x0;
uint32_t m_stm_resource_size_available = 0x0;
uint8_t *stm_resource_heap = NULL;
uint32_t m_stm_state = 0;
/*
* Handle single Resource to see if it can be merged into Record.
*
* @param resource A pointer to resource node to be added
* @param record A pointer to record node to be merged
*
* @retval true resource handled
* @retval false resource is not handled
*/
static bool handle_single_resource(STM_RSC *resource, STM_RSC *record)
{
uint64_t resource_lo = 0;
uint64_t resource_hi = 0;
uint64_t record_lo = 0;
uint64_t record_hi = 0;
// Calling code is responsible for making sure that
// Resource->Header.RscType == (*Record)->Header.RscType
// thus we use just one of them as switch variable.
switch (resource->header.rsc_type) {
case MEM_RANGE:
case MMIO_RANGE:
resource_lo = resource->mem.base;
resource_hi = resource->mem.base + resource->mem.length;
record_lo = record->mem.base;
record_hi = record->mem.base + record->mem.length;
if (resource->mem.rwx_attributes != record->mem.rwx_attributes) {
if ((resource_lo == record_lo) && (resource_hi == record_hi)) {
record->mem.rwx_attributes = resource->mem.rwx_attributes
| record->mem.rwx_attributes;
return true;
} else {
return false;
}
}
break;
case IO_RANGE:
case TRAPPED_IO_RANGE:
resource_lo = (uint64_t)resource->io.base;
resource_hi = (uint64_t)resource->io.base + (uint64_t)resource->io.length;
record_lo = (uint64_t)record->io.base;
record_hi = (uint64_t)record->io.base + (uint64_t)record->io.length;
break;
case PCI_CFG_RANGE:
if ((resource->pci_cfg.originating_bus_number
!= record->pci_cfg.originating_bus_number)
|| (resource->pci_cfg.last_node_index != record->pci_cfg.last_node_index))
return false;
if (memcmp(resource->pci_cfg.pci_device_path, record->pci_cfg.pci_device_path,
sizeof(STM_PCI_DEVICE_PATH_NODE)
* (resource->pci_cfg.last_node_index + 1))
!= 0) {
return false;
}
resource_lo = (uint64_t)resource->pci_cfg.base;
resource_hi =
(uint64_t)resource->pci_cfg.base + (uint64_t)resource->pci_cfg.length;
record_lo = (uint64_t)record->pci_cfg.base;
record_hi = (uint64_t)record->pci_cfg.base + (uint64_t)record->pci_cfg.length;
if (resource->pci_cfg.rw_attributes != record->pci_cfg.rw_attributes) {
if ((resource_lo == record_lo) && (resource_hi == record_hi)) {
record->pci_cfg.rw_attributes = resource->pci_cfg.rw_attributes
| record->pci_cfg.rw_attributes;
return true;
} else {
return false;
}
}
break;
case MACHINE_SPECIFIC_REG:
// Special case - merge MSR masks in place.
if (resource->msr.msr_index != record->msr.msr_index)
return false;
record->msr.read_mask |= resource->msr.read_mask;
record->msr.write_mask |= resource->msr.write_mask;
return true;
default:
return false;
}
// If resources are disjoint
if ((resource_hi < record_lo) || (resource_lo > record_hi))
return false;
// If resource is consumed by record.
if ((resource_lo >= record_lo) && (resource_hi <= record_hi))
return true;
// Resources are overlapping.
// Resource and record are merged.
resource_lo = (resource_lo < record_lo) ? resource_lo : record_lo;
resource_hi = (resource_hi > record_hi) ? resource_hi : record_hi;
switch (resource->header.rsc_type) {
case MEM_RANGE:
case MMIO_RANGE:
record->mem.base = resource_lo;
record->mem.length = resource_hi - resource_lo;
break;
case IO_RANGE:
case TRAPPED_IO_RANGE:
record->io.base = (uint64_t)resource_lo;
record->io.length = (uint64_t)(resource_hi - resource_lo);
break;
case PCI_CFG_RANGE:
record->pci_cfg.base = (uint64_t)resource_lo;
record->pci_cfg.length = (uint64_t)(resource_hi - resource_lo);
break;
default:
return false;
}
return true;
}
/*
* Add resource node.
*
* @param Resource A pointer to resource node to be added
*/
static void add_single_resource(STM_RSC *resource)
{
STM_RSC *record;
record = (STM_RSC *)m_stm_resources_ptr;
while (true) {
if (record->header.rsc_type == END_OF_RESOURCES)
break;
// Go to next record if resource and record types don't match.
if (resource->header.rsc_type != record->header.rsc_type) {
record = (STM_RSC *)((void *)record + record->header.length);
continue;
}
// Record is handled inside of procedure - don't adjust.
if (handle_single_resource(resource, record))
return;
record = (STM_RSC *)((void *)record + record->header.length);
}
// Add resource to the end of area.
memcpy(m_stm_resources_ptr + m_stm_resource_size_used - sizeof(m_rsc_end_node),
resource, resource->header.length);
memcpy(m_stm_resources_ptr + m_stm_resource_size_used - sizeof(m_rsc_end_node)
+ resource->header.length,
&m_rsc_end_node, sizeof(m_rsc_end_node));
m_stm_resource_size_used += resource->header.length;
m_stm_resource_size_available = m_stm_resource_total_size - m_stm_resource_size_used;
}
/*
* Add resource list.
*
* @param resource_list A pointer to resource list to be added
* @param num_entries Optional number of entries.
* If 0, list must be terminated by END_OF_RESOURCES.
*/
static void add_resource(STM_RSC *resource_list, uint32_t num_entries)
{
uint32_t count;
uint32_t index;
STM_RSC *resource;
if (num_entries == 0)
count = 0xFFFFFFFF;
else
count = num_entries;
resource = resource_list;
for (index = 0; index < count; index++) {
if (resource->header.rsc_type == END_OF_RESOURCES)
return;
add_single_resource(resource);
resource = (STM_RSC *)((void *)resource + resource->header.length);
}
}
/*
* Validate resource list.
*
* @param resource_list A pointer to resource list to be added
* @param num_entries Optional number of entries.
* If 0, list must be terminated by END_OF_RESOURCES.
*
* @retval true resource valid
* @retval false resource invalid
*/
static bool validate_resource(STM_RSC *resource_list, uint32_t num_entries)
{
uint32_t count;
uint32_t index;
STM_RSC *resource;
uint32_t sub_index;
// If NumEntries == 0 make it very big. Scan will be terminated by
// END_OF_RESOURCES.
if (num_entries == 0)
count = 0xFFFFFFFF;
else
count = num_entries;
// Start from beginning of resource list.
resource = resource_list;
for (index = 0; index < count; index++) {
printk(BIOS_DEBUG, "STM: %s (%u) - RscType(%x) length(0x%x)\n", __func__, index,
resource->header.rsc_type, resource->header.length);
// Validate resource.
switch (resource->header.rsc_type) {
case END_OF_RESOURCES:
if (resource->header.length != sizeof(STM_RSC_END))
return false;
// If we are passed actual number of resources to add,
// END_OF_RESOURCES structure between them is considered
// an error. If NumEntries == 0 END_OF_RESOURCES is a
// termination.
if (num_entries != 0)
return false;
// If NumEntries == 0 and list reached end - return
// success.
return true;
case MEM_RANGE:
case MMIO_RANGE:
printk(BIOS_DEBUG, "STM: %s - MEM (0x%0llx, 0x%0llx)\n", __func__,
resource->mem.base, resource->mem.length);
if (resource->header.length != sizeof(STM_RSC_MEM_DESC))
return false;
if (resource->mem.rwx_attributes > FULL_ACCS)
return false;
break;
case IO_RANGE:
case TRAPPED_IO_RANGE:
if (resource->header.length != sizeof(STM_RSC_IO_DESC))
return false;
if ((resource->io.base + resource->io.length) > 0xFFFF)
return false;
break;
case PCI_CFG_RANGE:
printk(BIOS_DEBUG, "STM: %s - PCI (0x%02x, 0x%08x, 0x%02x, 0x%02x)\n",
__func__, resource->pci_cfg.originating_bus_number,
resource->pci_cfg.last_node_index,
resource->pci_cfg.pci_device_path[0].pci_device,
resource->pci_cfg.pci_device_path[0].pci_function);
if (resource->header.length
!= sizeof(STM_RSC_PCI_CFG_DESC)
+ (sizeof(STM_PCI_DEVICE_PATH_NODE)
* resource->pci_cfg.last_node_index))
return false;
for (sub_index = 0; sub_index <= resource->pci_cfg.last_node_index;
sub_index++) {
if ((resource->pci_cfg.pci_device_path[sub_index].pci_device
> 0x1F)
|| (resource->pci_cfg.pci_device_path[sub_index]
.pci_function
> 7))
return false;
}
if ((resource->pci_cfg.base + resource->pci_cfg.length) > 0x1000)
return false;
break;
case MACHINE_SPECIFIC_REG:
if (resource->header.length != sizeof(STM_RSC_MSR_DESC))
return false;
break;
default:
printk(BIOS_DEBUG, "STM: %s - Unknown RscType(%x)\n", __func__,
resource->header.rsc_type);
return false;
}
resource = (STM_RSC *)((void *)resource + resource->header.length);
}
return true;
}
/*
* Get resource list.
* EndResource is excluded.
*
* @param resou rce_list A pointer to resource list to be added
* @param num_entries Optional number of entries.
* If 0, list must be terminated by END_OF_RESOURCES.
*
* @retval true resource valid
* @retval false resource invalid
*/
static uint32_t get_resource_size(STM_RSC *resource_list, uint32_t num_entries)
{
uint32_t count;
uint32_t index;
STM_RSC *resource;
resource = resource_list;
// If NumEntries == 0 make it very big. Scan will be terminated by
// END_OF_RESOURCES.
if (num_entries == 0)
count = 0xFFFFFFFF;
else
count = num_entries;
// Start from beginning of resource list.
resource = resource_list;
for (index = 0; index < count; index++) {
if (resource->header.rsc_type == END_OF_RESOURCES)
break;
resource = (STM_RSC *)((void *)resource + resource->header.length);
}
return (uint32_t)((uint32_t)resource - (uint32_t)resource_list);
}
/*
* Add resources in list to database. Allocate new memory areas as needed.
*
* @param resource_list A pointer to resource list to be added
* @param num_entries Optional number of entries.
* If 0, list must be terminated by END_OF_RESOURCES.
*
* @retval SUCCESS If resources are added
* @retval INVALID_PARAMETER If nested procedure detected resource failure
* @retval OUT_OF_RESOURCES If nested procedure returned it and we cannot
* allocate more areas.
*/
int add_pi_resource(STM_RSC *resource_list, uint32_t num_entries)
{
size_t resource_size;
printk(BIOS_DEBUG, "STM: %s - Enter\n", __func__);
if (!validate_resource(resource_list, num_entries))
return -1; // INVALID_PARAMETER;
resource_size = get_resource_size(resource_list, num_entries);
printk(BIOS_DEBUG, "STM: ResourceSize - 0x%08x\n", (int)resource_size);
if (resource_size == 0)
return -1; // INVALID_PARAMETER;
if (m_stm_resources_ptr == NULL) {
// Copy EndResource for initialization
m_stm_resources_ptr = stm_resource_heap;
m_stm_resource_total_size = CONFIG_BIOS_RESOURCE_LIST_SIZE;
memset(m_stm_resources_ptr, 0, CONFIG_BIOS_RESOURCE_LIST_SIZE);
memcpy(m_stm_resources_ptr, &m_rsc_end_node, sizeof(m_rsc_end_node));
m_stm_resource_size_used = sizeof(m_rsc_end_node);
m_stm_resource_size_available =
m_stm_resource_total_size - sizeof(m_rsc_end_node);
wbinvd(); // force to memory
} else {
if (m_stm_resource_size_available < resource_size) {
printk(BIOS_DEBUG,
"STM: ERROR - not enough space for SMM resource list\n");
return -1; // OUT_OF_RESOURCES
}
}
// Check duplication
add_resource(resource_list, num_entries);
return 0; // SUCCESS;
}
/*
* Delete resources in list to database.
*
* @param resource_list A pointer to resource list to be deleted
* NULL means delete all resources.
* @param num_entries Optional number of entries.
* If 0, list must be terminated by END_OF_RESOURCES.
*
* @retval SUCCESS If resources are deleted
* @retval INVALID_PARAMETER If nested procedure detected resource failure
*/
int32_t delete_pi_resource(STM_RSC *resource_list, uint32_t num_entries)
{
if (resource_list != NULL) {
// ASSERT (false);
return -1; // UNSUPPORTED;
}
// Delete all
memcpy(m_stm_resources_ptr, &m_rsc_end_node, sizeof(m_rsc_end_node));
m_stm_resource_size_used = sizeof(m_rsc_end_node);
m_stm_resource_size_available = m_stm_resource_total_size - sizeof(m_rsc_end_node);
return 0; // SUCCESS;
}
/*
* Get BIOS resources.
*
* @param resource_list A pointer to resource list to be filled
* @param resource_size On input it means size of resource list input.
* On output it means size of resource list filled,
* or the size of resource list to be filled if size is
* too small.
*
* @retval SUCCESS If resources are returned.
* @retval BUFFER_TOO_SMALL If resource list buffer is too small to hold
* the whole resource list.
*/
int32_t get_pi_resource(STM_RSC *resource_list, uint32_t *resource_size)
{
if (*resource_size < m_stm_resource_size_used) {
*resource_size = (uint32_t)m_stm_resource_size_used;
return -1; // BUFFER_TOO_SMALL;
}
memcpy(resource_list, m_stm_resources_ptr, m_stm_resource_size_used);
*resource_size = (uint32_t)m_stm_resource_size_used;
return 0; // SUCCESS;
}
/*
* Get 4K page aligned VMCS size.
* @return 4K page aligned VMCS size
*/
static uint32_t get_vmcs_size(void)
{
uint32_t this_vmcs_size;
VMX_BASIC_MSR msr_data64;
int stm_support;
msr_data64.msr = rdmsr(IA32_VMX_BASIC_MSR);
this_vmcs_size = msr_data64.bits.vmcs_size;
stm_support = msr_data64.bits.stm_supported;
printk(BIOS_DEBUG, "STM: %s: Size %d StmSupport %d\n", __func__, this_vmcs_size,
stm_support);
// VMCS require 0x1000 alignment
this_vmcs_size = STM_PAGES_TO_SIZE(STM_SIZE_TO_PAGES(this_vmcs_size));
return this_vmcs_size;
}
/*
* Create 4G page table for STM.
* 2M PTEs for x86_64 or 2M PTEs for x86_32.
*
* @param pageable_base The page table base in MSEG
*/
void stm_gen_4g_pagetable_x64(uint32_t pagetable_base)
{
uint32_t index;
uint32_t sub_index;
uint64_t *pde;
uint64_t *pte;
uint64_t *pml4;
pml4 = (uint64_t *)(uint32_t)pagetable_base;
pagetable_base += PTP_SIZE;
*pml4 = pagetable_base | IA32_PG_RW | IA32_PG_P;
pde = (uint64_t *)(uint32_t)pagetable_base;
pagetable_base += PTP_SIZE;
pte = (uint64_t *)(uint32_t)pagetable_base;
for (index = 0; index < 4; index++) {
*pde = pagetable_base | IA32_PG_RW | IA32_PG_P;
pde++;
pagetable_base += PTP_SIZE;
for (sub_index = 0; sub_index < SIZE_4KB / sizeof(*pte); sub_index++) {
*pte = (((index << 9) + sub_index) << 21) | IA32_PG_PS | IA32_PG_RW
| IA32_PG_P;
pte++;
}
}
}
/*
* Check STM image size.
*
* @param stm_image STM image
* @param stm_imageSize STM image size
*
* @retval true check pass
* @retval false check fail
*/
bool stm_check_stm_image(void *stm_image, uint32_t stm_imagesize)
{
uint32_t min_mseg_size;
STM_HEADER *stm_header;
stm_header = (STM_HEADER *)stm_image;
// Get Minimal required Mseg size
min_mseg_size =
(STM_PAGES_TO_SIZE(STM_SIZE_TO_PAGES(stm_header->sw_stm_hdr.static_image_size))
+ stm_header->sw_stm_hdr.additional_dynamic_memory_size
+ (stm_header->sw_stm_hdr.per_proc_dynamic_memory_size + get_vmcs_size() * 2)
* mp_state.cpu_count);
if (min_mseg_size < stm_imagesize)
min_mseg_size = stm_imagesize;
if (stm_header->hw_stm_hdr.cr3_offset >= stm_header->sw_stm_hdr.static_image_size) {
// We will create page table, just in case that SINIT does not
// create it.
if (min_mseg_size < stm_header->hw_stm_hdr.cr3_offset + STM_PAGES_TO_SIZE(6)) {
min_mseg_size =
stm_header->hw_stm_hdr.cr3_offset + STM_PAGES_TO_SIZE(6);
}
}
// Check if it exceeds MSEG size
if (min_mseg_size > CONFIG_MSEG_SIZE) {
printk(BIOS_ERR,
"STM: ERROR - Configured MSEG size 0x%x less than required MSEG size 0x%x\n",
CONFIG_MSEG_SIZE, min_mseg_size);
return false;
}
return true;
}
/*
* This function return BIOS STM resource.
* Produced by SmmStm.
* Comsumed by SmmMpService when Init.
*
* @return BIOS STM resource
*/
void *get_stm_resource(void)
{
return m_stm_resources_ptr;
}

View file

@ -0,0 +1,120 @@
/* @file
* SMM STM support
*
* Copyright (c) 2015 - 2016, Intel Corporation. All rights reserved.
* This program and the accompanying materials are licensed and made
* available under the terms and conditions of the BSD License which
* accompanies this distribution. The full text of the license may
* be found at http://opensource.org/licenses/bsd-license.php.
*
* THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
* WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED
*
*/
#ifndef _SMM_STM_H_
#define _SMM_STM_H_
#include <cpu/x86/msr.h>
#include "StmApi.h"
/*
* Load STM image.
*
* @retval SUCCESS STM is loaded to MSEG
* @retval BUFFER_TOO_SMALL MSEG is too small
* @retval UNSUPPORTED MSEG is not enabled
*/
int load_stm_image(uintptr_t mseg);
void stm_setup(
uintptr_t mseg, int cpu, int num_cpus, uintptr_t smbase,
uintptr_t smbase_base, uint32_t offset32);
/*
* Add resources in list to database. Allocate new memory areas as needed.
*
* @param resource_list A pointer to resource list to be added
* @param num_entries Optional number of entries.
* If 0, list must be terminated by END_OF_RESOURCES.
*
* @retval SUCCESS If resources are added
* @retval INVALID_PARAMETER If nested procedure detected resource failure
* @retval OUT_OF_RESOURCES If nested procedure returned it and we cannot
* allocate more areas.
*/
int add_pi_resource(STM_RSC *resource_list, uint32_t num_entries);
/*
* Delete resources in list to database.
*
* @param resource_list A pointer to resource list to be deleted
* NULL means delete all resources.
* @param num_entries Optional number of entries.
* If 0, list must be terminated by END_OF_RESOURCES.
*
* @retval SUCCESS If resources are deleted
* @retval NVALID_PARAMETER If nested procedure detected resource fail
*/
int delete_pi_resource(STM_RSC *resource_list, uint32_t num_entries);
/*
* Get BIOS resources.
*
* @param resource_list A pointer to resource list to be filled
* @param resource_size On input it means size of resource list input.
* On output it means size of resource list filled,
* or the size of resource list to be filled if
* size is too small.
*
* @retval SUCCESS If resources are returned.
* @retval BUFFER_TOO_SMALL If resource list buffer is too small to
* hold the whole resources.
*/
int get_pi_resource(STM_RSC *resource_list, uint32_t *resource_size);
/*
* This function notifies the STM of a resource change.
*
* @param stm_resource BIOS STM resource
*/
void notify_stm_resource_change(void *stm_resource);
/*
* This function returns the pointer to the STM BIOS resource list.
*
* @return BIOS STM resource
*/
void *get_stm_resource(void);
void setup_smm_descriptor(void *smbase, void *base_smbase, int32_t apic_id,
int32_t entry32_off);
/*
* Check STM image size.
*
* @param stm_image STM image
* @param stm_image_size STM image size
*
* @retval true check pass
* @retval false check fail
*/
bool stm_check_stm_image(void *stm_image, uint32_t stm_image_size);
/*
* Create 4G page table for STM.
* 4M Non-PAE page table in IA32 version.
*
* @param page_table_base The page table base in MSEG
*/
void stm_gen_4g_pagetable_ia32(uint32_t pagetable_base);
/*
* Create 4G page table for STM.
* 2M PAE page table in X64 version.
*
* @param pagetable_base The page table base in MSEG
*/
void stm_gen_4g_pagetable_x64(uint32_t pagetable_base);
#endif

View file

@ -0,0 +1,726 @@
/* @file
* STM API definition
*
* Copyright (c) 2015, Intel Corporation. All rights reserved.
* This program and the accompanying materials are licensed and made available
* under the terms and conditions of the BSD License which accompanies this
* distribution. The full text of the license may be found at
* http://opensource.org/licenses/bsd-license.php.
*
* THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
* WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND,
* EITHER EXPRESS OR IMPLIED.
*
*/
#ifndef _STM_API_H_
#define _STM_API_H_
#include <stdint.h>
// definition in STM spec
#define STM_SPEC_VERSION_MAJOR 1
#define STM_SPEC_VERSION_MINOR 0
#pragma pack(push, 1)
#define STM_HARDWARE_FIELD_FILL_TO_2K (2048 - sizeof(uint32_t) * 8)
typedef struct {
uint32_t stm_header_revision;
uint32_t monitor_features;
uint32_t gdtr_limit;
uint32_t gdtr_base_offset;
uint32_t cs_selector;
uint32_t eip_offset;
uint32_t esp_offset;
uint32_t cr3_offset;
uint8_t reserved[STM_HARDWARE_FIELD_FILL_TO_2K];
} HARDWARE_STM_HEADER;
#define STM_FEATURES_IA32E 0x1
typedef struct {
uint32_t intel_64mode_supported : 1;
uint32_t ept_supported : 1;
uint32_t mbz : 30;
} STM_FEAT;
typedef struct {
uint8_t stm_spec_ver_major;
uint8_t stm_pec_ver_minor;
uint16_t mbz;
uint32_t static_image_size;
uint32_t per_proc_dynamic_memory_size;
uint32_t additional_dynamic_memory_size;
STM_FEAT stm_features;
uint32_t number_of_rev_ids;
uint32_t stm_smm_rev_id[1];
// The total STM_HEADER should be 4K.
} SOFTWARE_STM_HEADER;
typedef struct {
HARDWARE_STM_HEADER hw_stm_hdr;
SOFTWARE_STM_HEADER sw_stm_hdr;
} STM_HEADER;
#define SHA1 1
#define SHA256 2
typedef struct {
uint64_t bios_component_base;
uint32_t image_size;
uint32_t hash_algorithm; // SHA1 or SHA256
uint8_t hash[32];
} TXT_BIOS_COMPONENT_STATUS;
#define PAGE_SIZE 4096
typedef struct {
uint32_t image_size;
uint32_t reserved;
uint64_t image_page_base[1]; //[NumberOfPages];
} TXT_BIOS_COMPONENT_UPDATE;
typedef struct {
uint64_t spe_rip;
uint64_t spe_rsp;
uint16_t spe_ss;
uint16_t page_violation_exception : 1;
uint16_t msr_violation_exception : 1;
uint16_t register_violation_exception : 1;
uint16_t io_violation_exception : 1;
uint16_t pci_violation_exception : 1;
uint16_t reserved1 : 11;
uint32_t reserved2;
} STM_PROTECTION_EXCEPTION_HANDLER;
typedef struct {
uint8_t execution_disable_outside_smrr : 1;
uint8_t intel_64mode : 1;
uint8_t cr4_pae : 1;
uint8_t cr4_pse : 1;
uint8_t reserved1 : 4;
} STM_SMM_ENTRY_STATE;
typedef struct {
uint8_t smram_to_vmcs_restore_required : 1; // BIOS restore hint
uint8_t reinitialize_vmcs_required : 1; // BIOS request
uint8_t reserved2 : 6;
} STM_SMM_RESUME_STATE;
typedef struct {
uint8_t domain_type : 4; // STM input to BIOS on each SM
uint8_t x_state_policy : 2; // STM input to BIOS on each SMI
uint8_t ept_enabled : 1;
uint8_t reserved3 : 1;
} STM_SMM_STATE;
typedef struct {
uint64_t signature;
uint16_t size;
uint8_t smm_descriptor_ver_major;
uint8_t smm_descriptor_ver_minor;
uint32_t local_apic_id;
STM_SMM_ENTRY_STATE smm_entry_state;
STM_SMM_RESUME_STATE smm_resume_state;
STM_SMM_STATE stm_smm_state;
uint8_t reserved4;
uint16_t smm_cs;
uint16_t smm_ds;
uint16_t smm_ss;
uint16_t smm_other_segment;
uint16_t smm_tr;
uint16_t reserved5;
uint64_t smm_cr3;
uint64_t smm_stm_setup_rip;
uint64_t smm_stm_teardown_rip;
uint64_t smm_smi_handler_rip;
uint64_t smm_smi_handler_rsp;
uint64_t smm_gdt_ptr;
uint32_t smm_gdt_size;
uint32_t required_stm_smm_rev_id;
STM_PROTECTION_EXCEPTION_HANDLER stm_protection_exception_handler;
uint64_t reserved6;
uint64_t bios_hw_resource_requirements_ptr;
// extend area
uint64_t acpi_rsdp;
uint8_t physical_address_bits;
} TXT_PROCESSOR_SMM_DESCRIPTOR;
#define TXT_PROCESSOR_SMM_DESCRIPTOR_SIGNATURE "TXTPSSIG"
#define TXT_PROCESSOR_SMM_DESCRIPTOR_VERSION_MAJOR 1
#define TXT_PROCESSOR_SMM_DESCRIPTOR_VERSION_MINOR 0
#define SMM_PSD_OFFSET 0xfb00
typedef enum {
TxtSmmPageViolation = 1,
TxtSmmMsrViolation,
TxtSmmRegisterViolation,
TxtSmmIoViolation,
TxtSmmPciViolation
} TXT_SMM_PROTECTION_EXCEPTION_TYPE;
typedef struct {
uint32_t rdi;
uint32_t rsi;
uint32_t rbp;
uint32_t rdx;
uint32_t rcx;
uint32_t rbx;
uint32_t rax;
uint32_t cr3;
uint32_t cr2;
uint32_t cr0;
uint32_t vmcs_exit_instruction_info;
uint32_t vmcs_exit_instruction_length;
uint64_t vmcs_exit_qualification;
uint32_t error_code; // TXT_SMM_PROTECTION_EXCEPTION_TYPE
uint32_t rip;
uint32_t cs;
uint32_t rflags;
uint32_t rsp;
uint32_t ss;
} STM_PROTECTION_EXCEPTION_STACK_FRAME_IA32;
typedef struct {
uint64_t r15;
uint64_t r14;
uint64_t r13;
uint64_t r12;
uint64_t r11;
uint64_t r10;
uint64_t r9;
uint64_t r8;
uint64_t rdi;
uint64_t rsi;
uint64_t rbp;
uint64_t rdx;
uint64_t rcx;
uint64_t rbx;
uint64_t rax;
uint64_t cr8;
uint64_t cr3;
uint64_t cr2;
uint64_t cr0;
uint64_t vmcs_exit_instruction_info;
uint64_t vmcs_exit_instruction_length;
uint64_t vmcs_exit_qualification;
uint64_t error_code; // TXT_SMM_PROTECTION_EXCEPTION_TYPE
uint64_t rip;
uint64_t cs;
uint64_t rflags;
uint64_t rsp;
uint64_t ss;
} STM_PROTECTION_EXCEPTION_STACK_FRAME_X64;
typedef union {
STM_PROTECTION_EXCEPTION_STACK_FRAME_IA32 *ia32_stack_frame;
STM_PROTECTION_EXCEPTION_STACK_FRAME_X64 *x64_stack_frame;
} STM_PROTECTION_EXCEPTION_STACK_FRAME;
#define STM_SMM_REV_ID 0x80010100
typedef struct _STM_SMM_CPU_STATE { // Writable?
uint8_t reserved1[0x1d0]; // fc00h
uint32_t gdt_base_hi_dword; // fdd0h : NO
uint32_t ldt_base_hi_dword; // fdd4h : NO
uint32_t idt_base_hi_dword; // fdd8h : NO
uint8_t reserved2[0x4]; // fddch
uint64_t io_rdi; // fde0h : NO
// - restricted
uint64_t io_eip; // fde8h : YES
uint64_t io_rcx; // fdf0h : NO
// - restricted
uint64_t io_rsi; // fdf8h : NO
// - restricted
uint8_t reserved3[0x40]; // fe00h
uint32_t cr4; // fe40h : NO
uint8_t reserved4[0x48]; // fe44h
uint32_t gdt_base_lo_dword; // fe8ch : NO
uint32_t gdt_limit; // fe90h : NO
// - RESTRICTED
uint32_t idt_base_lo_dword; // fe94h : NO
uint32_t idt_limit; // fe98h : NO
// - RESTRICTED
uint32_t ldt_base_lo_dword; // fe9ch : NO
uint32_t ldt_limit; // fea0h : NO
// - RESTRICTED
uint32_t ldt_info; // fea4h : NO
// - RESTRICTED
uint8_t reserved5[0x30]; // fea8h
uint64_t eptp; // fed8h : NO
uint32_t enabled_ept; // fee0h : NO
uint8_t reserved6[0x14]; // fee4h
uint32_t smbase; // fef8h : YES
// - NO for STM
uint32_t smm_rev_id; // fefch : NO
uint16_t io_restart; // ff00h : YES
uint16_t auto_halt_restart; // ff02h : YES
uint8_t reserved7[0x18]; // ff04h
uint64_t r15; // ff1ch : YES
uint64_t r14; // ff24h : YES
uint64_t r13; // ff2ch : YES
uint64_t r12; // ff34h : YES
uint64_t r11; // ff3ch : YES
uint64_t r10; // ff44h : YES
uint64_t r9; // ff4ch : YES
uint64_t r8; // ff54h : YES
uint64_t rax; // ff5ch : YES
uint64_t rcx; // ff64h : YES
uint64_t rdx; // ff6ch : YES
uint64_t rbx; // ff74h : YES
uint64_t rsp; // ff7ch : YES
uint64_t rbp; // ff84h : YES
uint64_t rsi; // ff8ch : YES
uint64_t rdi; // ff94h : YES
uint64_t io_mem_addr; // ff9ch : NO
uint32_t io_misc; // ffa4h : NO
uint32_t es; // ffa8h : NO
uint32_t cs; // ffach : NO
uint32_t ss; // ffb0h : NO
uint32_t ds; // ffb4h : NO
uint32_t fs; // ffb8h : NO
uint32_t gs; // ffbch : NO
uint32_t ldtr; // ffc0h : NO
uint32_t tr; // ffc4h : NO
uint64_t dr7; // ffc8h : NO
uint64_t dr6; // ffd0h : NO
uint64_t rip; // ffd8h : YES
uint64_t ia32_efer; // ffe0h : YES
// - NO for STM
uint64_t rflags; // ffe8h : YES
uint64_t cr3; // fff0h : NO
uint64_t cr0; // fff8h : NO
} STM_SMM_CPU_STATE;
// STM Mapping
typedef struct {
uint64_t physical_address;
uint64_t virtual_ddress;
uint32_t Page_count;
uint32_t Pat_cache_type;
} STM_MAP_ADDRESS_RANGE_DESCRIPTOR;
#define ST_UC 0x00
#define WC 0x01
#define WT 0x04
#define WP 0x05
#define WB 0x06
#define UC 0x07
#define FOLLOW_MTRR 0xFFFFFFFF
typedef struct {
uint64_t virtual_address;
uint32_t length;
} STM_UNMAP_ADDRESS_RANGE_DESCRIPTOR;
typedef struct {
uint64_t interrupted_guest_virtual_address;
uint32_t length;
uint64_t interrupted_cr3;
uint64_t interrupted_eptp;
uint32_t map_to_smm_guest : 2;
uint32_t interrupted_cr4_pae : 1;
uint32_t interrupted_cr4_pse : 1;
uint32_t interrupted_ia32e_mode : 1;
uint32_t reserved1 : 27;
uint32_t reserved2;
uint64_t physical_address;
uint64_t smm_guest_virtual_address;
} STM_ADDRESS_LOOKUP_DESCRIPTOR;
#define DO_NOT_MAP 0
#define ONE_TO_ONE 1
#define VIRTUAL_ADDRESS_SPECIFIED 3
// STM_RESOURCE_LIST
#define END_OF_RESOURCES 0
#define MEM_RANGE 1
#define IO_RANGE 2
#define MMIO_RANGE 3
#define MACHINE_SPECIFIC_REG 4
#define PCI_CFG_RANGE 5
#define TRAPPED_IO_RANGE 6
#define ALL_RESOURCES 7
#define REGISTER_VIOLATION 8
#define MAX_DESC_TYPE 8
typedef struct {
uint32_t rsc_type;
uint16_t length;
uint16_t return_status : 1;
uint16_t reserved : 14;
uint16_t ignore_resource : 1;
} STM_RSC_DESC_HEADER;
typedef struct {
STM_RSC_DESC_HEADER Hdr;
uint64_t resource_list_continuation;
} STM_RSC_END;
// byte granular Memory range support
#define STM_RSC_BGM 0x4
typedef struct {
STM_RSC_DESC_HEADER hdr;
uint64_t base;
uint64_t length;
uint32_t rwx_attributes : 3;
uint32_t reserved : 29;
uint32_t reserved_2;
} STM_RSC_MEM_DESC;
#define STM_RSC_MEM_R 0x1
#define STM_RSC_MEM_W 0x2
#define STM_RSC_MEM_X 0x4
typedef struct {
STM_RSC_DESC_HEADER hdr;
uint16_t base;
uint16_t length;
uint32_t reserved;
} STM_RSC_IO_DESC;
// byte granular MMIO range support
#define STM_RSC_BGI 0x2
typedef struct {
STM_RSC_DESC_HEADER hdr;
uint64_t base;
uint64_t length;
uint32_t rwx_attributes : 3;
uint32_t reserved : 29;
uint32_t reserved_2;
} STM_RSC_MMIO_DESC;
#define STM_RSC_MMIO_R 0x1
#define STM_RSC_MMIO_W 0x2
#define STM_RSC_MMIO_X 0x4
typedef struct {
STM_RSC_DESC_HEADER hdr;
uint32_t msr_index;
uint32_t kernel_mode_processing : 1;
uint32_t reserved : 31;
uint64_t read_mask;
uint64_t write_mask;
} STM_RSC_MSR_DESC;
// bit granular MSR resource support
#define STM_RSC_MSR 0x8
typedef struct {
uint8_t type; // must be 1, indicating Hardware Device Path
uint8_t subtype; // must be 1, indicating PCI
uint16_t length; // sizeof(STM_PCI_DEVICE_PATH_NODE) which is 6
uint8_t pci_function;
uint8_t pci_device;
} STM_PCI_DEVICE_PATH_NODE;
typedef struct {
STM_RSC_DESC_HEADER hdr;
uint16_t rw_attributes : 2;
uint16_t reserved : 14;
uint16_t base;
uint16_t length;
uint8_t originating_bus_number;
uint8_t last_node_index;
STM_PCI_DEVICE_PATH_NODE pci_device_path[1];
// STM_PCI_DEVICE_PATH_NODE PciDevicePath[LastNodeIndex + 1];
} STM_RSC_PCI_CFG_DESC;
#define STM_RSC_PCI_CFG_R 0x1
#define STM_RSC_PCI_CFG_W 0x2
typedef struct {
STM_RSC_DESC_HEADER hdr;
uint16_t base;
uint16_t length;
uint16_t in : 1;
uint16_t out : 1;
uint16_t api : 1;
uint16_t reserved1 : 13;
uint16_t reserved2;
} STM_RSC_TRAPPED_IO_DESC;
typedef struct {
STM_RSC_DESC_HEADER hdr;
} STM_RSC_ALL_RESOURCES_DESC;
typedef struct {
STM_RSC_DESC_HEADER hdr;
uint32_t register_type;
uint32_t reserved;
uint64_t readMask;
uint64_t write_mask;
} STM_REGISTER_VIOLATION_DESC;
typedef enum {
stm_register_cr0,
stm_register_cr2,
stm_register_cr3,
stm_register_cr4,
stm_register_cr8,
stm_register_max,
} STM_REGISTER_VIOLATION_TYPE;
typedef union {
STM_RSC_DESC_HEADER header;
STM_RSC_END end;
STM_RSC_MEM_DESC mem;
STM_RSC_IO_DESC io;
STM_RSC_MMIO_DESC mmio;
STM_RSC_MSR_DESC msr;
STM_RSC_PCI_CFG_DESC pci_cfg;
STM_RSC_TRAPPED_IO_DESC trapped_io;
STM_RSC_ALL_RESOURCES_DESC all;
STM_REGISTER_VIOLATION_DESC register_violation;
} STM_RSC;
// VMCS database
#define STM_VMCS_DATABASE_REQUEST_ADD 1
#define STM_VMCS_DATABASE_REQUEST_REMOVE 0
// Values for DomainType
// Interpreter of DomainType
#define DOMAIN_DISALLOWED_IO_OUT (1u << 0)
#define DOMAIN_DISALLOWED_IO_IN (1u << 1)
#define DOMAIN_INTEGRITY (1u << 2)
#define DOMAIN_CONFIDENTIALITY (1u << 3)
#define DOMAIN_UNPROTECTED 0x00
#define DOMAIN_INTEGRITY_PROT_OUT_IN (DOMAIN_INTEGRITY)
#define DOMAIN_FULLY_PROT_OUT_IN (DOMAIN_CONFIDENTIALITY | DOMAIN_INTEGRITY)
#define DOMAIN_FULLY_PROT \
(DOMAIN_CONFIDENTIALITY | DOMAIN_INTEGRITY | DOMAIN_DISALLOWED_IO_IN \
| DOMAIN_DISALLOWED_IO_OUT)
// Values for XStatePolicy
#define XSTATE_READWRITE 0x00
#define XSTATE_READONLY 0x01
#define XSTATE_SCRUB 0x03
typedef struct {
uint64_t vmcs_phys_pointer; // bits 11:0 are reserved and must be 0
uint32_t domain_type : 4;
uint32_t x_state_policy : 2;
uint32_t degradation_policy : 4;
uint32_t reserved1 : 22; // Must be 0
uint32_t add_or_remove;
} STM_VMCS_DATABASE_REQUEST;
// Event log
#define NEW_LOG 1
#define CONFIGURE_LOG 2
#define START_LOG 3
#define STOP_LOG 4
#define CLEAR_LOG 5
#define DELETE_LOG 6
typedef enum {
evt_log_started,
evt_log_stopped,
evt_log_invalid_parameter_detected,
evt_handled_protection_exception,
// unhandled protection exceptions result in reset & cannot be logged
evt_bios_access_to_unclaimed_resource,
evt_mle_resource_protection_granted,
evt_mle_resource_protection_denied,
evt_mle_resource_unprotect,
evt_mle_resource_unprotect_error,
evt_mle_domain_type_degraded,
// add more here
evt_mle_max,
// Not used
evt_invalid = 0xFFFFFFFF,
} EVENT_TYPE;
typedef struct {
uint32_t page_count;
uint64_t pages[1]; // number of elements is PageCount
} STM_EVENT_LOG_MANAGEMENT_REQUEST_DATA_LOG_BUFFER;
typedef union {
STM_EVENT_LOG_MANAGEMENT_REQUEST_DATA_LOG_BUFFER log_buffer;
uint32_t event_enable_bitmap; // bitmap of EVENT_TYPE
} STM_EVENT_LOG_MANAGEMENT_REQUEST_DATA;
typedef struct {
uint32_t sub_functionindex;
STM_EVENT_LOG_MANAGEMENT_REQUEST_DATA data;
} STM_EVENT_LOG_MANAGEMENT_REQUEST;
// VMCALL API Numbers
//
// API number convention: BIOS facing VMCALL interfaces have bit 16 clear
#define STM_API_MAP_ADDRESS_RANGE 0x00000001
#define STM_API_UNMAP_ADDRESS_RANGE 0x00000002
#define STM_API_ADDRESS_LOOKUP 0x00000003
#define STM_API_RETURN_FROM_PROTECTION_EXCEPTION 0x00000004
// API number convention: MLE facing VMCALL interfaces have bit 16 set
//
// The STM configuration lifecycle is as follows:
// 1. SENTER->SINIT->MLE: MLE begins execution with SMI disabled (masked).
// 2. MLE invokes InitializeProtectionVMCALL() to prepare STM for setup of
// initial protection profile. This is done on a single CPU and has global
// effect.
// 3. MLE invokes ProtectResourceVMCALL() to define the initial protection
// profile. The protection profile is global across all CPUs.
// 4. MLE invokes StartStmVMCALL() to enable the STM to begin receiving SMI
// events. This must be done on every logical CPU.
// 5. MLE may invoke ProtectResourceVMCALL() or UnProtectResourceVMCALL()
// during runtime as many times as necessary.
// 6. MLE invokes StopStmVMCALL() to disable the STM. SMI is again masked
// following StopStmVMCALL().
//
#define STM_API_START 0x00010001
#define STM_API_STOP 0x00010002
#define STM_API_PROTECT_RESOURCE 0x00010003
#define STM_API_UNPROTECT_RESOURCE 0x00010004
#define STM_API_GET_BIOS_RESOURCES 0x00010005
#define STM_API_MANAGE_VMCS_DATABASE 0x00010006
#define STM_API_INITIALIZE_PROTECTION 0x00010007
#define STM_API_MANAGE_EVENT_LOG 0x00010008
// Return codes
typedef uint32_t STM_STATUS;
#define STM_SUCCESS 0x00000000
#define SMM_SUCCESS 0x00000000
// all error codes have bit 31 set
// STM errors have bit 16 set
#define ERROR_STM_SECURITY_VIOLATION 0x80010001
#define ERROR_STM_CACHE_TYPE_NOT_SUPPORTED 0x80010002
#define ERROR_STM_PAGE_NOT_FOUND 0x80010003
#define ERROR_STM_BAD_CR3 0x80010004
#define ERROR_STM_PHYSICAL_OVER_4G 0x80010005
#define ERROR_STM_VIRTUAL_SPACE_TOO_SMALL 0x80010006
#define ERROR_STM_UNPROTECTABLE_RESOURCE 0x80010007
#define ERROR_STM_ALREADY_STARTED 0x80010008
#define ERROR_STM_WITHOUT_SMX_UNSUPPORTED 0x80010009
#define ERROR_STM_STOPPED 0x8001000A
#define ERROR_STM_BUFFER_TOO_SMALL 0x8001000B
#define ERROR_STM_INVALID_VMCS_DATABASE 0x8001000C
#define ERROR_STM_MALFORMED_RESOURCE_LIST 0x8001000D
#define ERROR_STM_INVALID_PAGECOUNT 0x8001000E
#define ERROR_STM_LOG_ALLOCATED 0x8001000F
#define ERROR_STM_LOG_NOT_ALLOCATED 0x80010010
#define ERROR_STM_LOG_NOT_STOPPED 0x80010011
#define ERROR_STM_LOG_NOT_STARTED 0x80010012
#define ERROR_STM_RESERVED_BIT_SET 0x80010013
#define ERROR_STM_NO_EVENTS_ENABLED 0x80010014
#define ERROR_STM_OUT_OF_RESOURCES 0x80010015
#define ERROR_STM_FUNCTION_NOT_SUPPORTED 0x80010016
#define ERROR_STM_UNPROTECTABLE 0x80010017
#define ERROR_STM_UNSUPPORTED_MSR_BIT 0x80010018
#define ERROR_STM_UNSPECIFIED 0x8001FFFF
// SMM errors have bit 17 set
#define ERROR_SMM_BAD_BUFFER 0x80020001
#define ERROR_SMM_INVALID_RSC 0x80020004
#define ERROR_SMM_INVALID_BUFFER_SIZE 0x80020005
#define ERROR_SMM_BUFFER_TOO_SHORT 0x80020006
#define ERROR_SMM_INVALID_LIST 0x80020007
#define ERROR_SMM_OUT_OF_MEMORY 0x80020008
#define ERROR_SMM_AFTER_INIT 0x80020009
#define ERROR_SMM_UNSPECIFIED 0x8002FFFF
// Errors that apply to both have bits 15, 16, and 17 set
#define ERROR_INVALID_API 0x80038001
#define ERROR_INVALID_PARAMETER 0x80038002
// STM TXT.ERRORCODE codes
#define STM_CRASH_PROTECTION_EXCEPTION 0xC000F001
#define STM_CRASH_PROTECTION_EXCEPTION_FAILURE 0xC000F002
#define STM_CRASH_DOMAIN_DEGRADATION_FAILURE 0xC000F003
#define STM_CRASH_BIOS_PANIC 0xC000E000
typedef struct {
uint32_t event_serial_number;
uint16_t type;
uint16_t lock : 1;
uint16_t valid : 1;
uint16_t read_by_mle : 1;
uint16_t wrapped : 1;
uint16_t reserved : 12;
} LOG_ENTRY_HEADER;
typedef struct {
uint32_t reserved;
} ENTRY_EVT_LOG_STARTED;
typedef struct {
uint32_t reserved;
} ENTRY_EVT_LOG_STOPPED;
typedef struct {
uint32_t vmcall_api_number;
} ENTRY_EVT_LOG_INVALID_PARAM;
typedef struct {
STM_RSC resource;
} ENTRY_EVT_LOG_HANDLED_PROTECTION_EXCEPTION;
typedef struct {
STM_RSC resource;
} ENTRY_EVT_BIOS_ACCESS_UNCLAIMED_RSC;
typedef struct {
STM_RSC resource;
} ENTRY_EVT_MLE_RSC_PROT_GRANTED;
typedef struct {
STM_RSC resource;
} ENTRY_EVT_MLE_RSC_PROT_DENIED;
typedef struct {
STM_RSC resource;
} ENTRY_EVT_MLE_RSC_UNPROT;
typedef struct {
STM_RSC resource;
} ENTRY_EVT_MLE_RSC_UNPROT_ERROR;
typedef struct {
uint64_t vmcs_phys_pointer;
uint8_t expected_domain_type;
uint8_t degraded_domain_type;
} ENTRY_EVT_MLE_DOMAIN_TYPE_DEGRADED;
typedef union {
ENTRY_EVT_LOG_STARTED started;
ENTRY_EVT_LOG_STOPPED stopped;
ENTRY_EVT_LOG_INVALID_PARAM invalid_param;
ENTRY_EVT_LOG_HANDLED_PROTECTION_EXCEPTION
handled_protection_exception;
ENTRY_EVT_BIOS_ACCESS_UNCLAIMED_RSC bios_unclaimed_rsc;
ENTRY_EVT_MLE_RSC_PROT_GRANTED mle_rsc_prot_granted;
ENTRY_EVT_MLE_RSC_PROT_DENIED mle_rsc_prot_denied;
ENTRY_EVT_MLE_RSC_UNPROT mle_rsc_unprot;
ENTRY_EVT_MLE_RSC_UNPROT_ERROR mle_rsc_unprot_error;
ENTRY_EVT_MLE_DOMAIN_TYPE_DEGRADED mle_domain_type_degraded;
} LOG_ENTRY_DATA;
typedef struct {
LOG_ENTRY_HEADER hdr;
LOG_ENTRY_DATA data;
} STM_LOG_ENTRY;
#define STM_LOG_ENTRY_SIZE 256
#define STM_CONFIG_SMI_UNBLOCKING_BY_VMX_OFF 0x1
// TXT debug
#define SW_SMI_STM_ADD_RUNTIME_RESOURCES_SUB_FUNC 0
#define SW_SMI_STM_READ_BIOS_RESOURCES_SUB_FUNC 1
#define SW_SMI_STM_REPLACE_BIOS_RESOURCES_SUB_FUNC 2
typedef struct {
uint32_t buffer_size;
uint32_t reserved;
// uint8_t Data[];
} TXT_BIOS_DEBUG;
#pragma pack(pop)
#endif

View file

@ -0,0 +1,192 @@
/* @file
* STM platform SMM resource
*
* Copyright (c) 2015, Intel Corporation. All rights reserved.
* This program and the accompanying materials are licensed and made
* available under the terms and conditions of the BSD License which
* accompanies this distribution. The full text of the license may be found
* at http://opensource.org/licenses/bsd-license.php.
*
* THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
* WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR
* IMPLIED.
*/
#include <stdint.h>
#include <security/intel/stm/StmApi.h>
#include <security/intel/stm/SmmStm.h>
#include <security/intel/stm/StmPlatformResource.h>
#if CONFIG(SOUTHBRIDGE_INTEL_COMMON_PMCLIB)
#include <southbridge/intel/common/pmutil.h>
#else
#include <soc/pm.h>
#endif
#include <cpu/x86/msr.h>
#include <console/console.h>
#define RDWR_ACCS 3
#define FULL_ACCS 7
// Fixed memory ranges
//
// TSEG memory!
static STM_RSC_MEM_DESC rsc_tseg_memory = {{MEM_RANGE, sizeof(STM_RSC_MEM_DESC)},
0,
0,
FULL_ACCS};
// Flash part
static STM_RSC_MEM_DESC rsc_spi_memory = {
{MEM_RANGE, sizeof(STM_RSC_MEM_DESC)},
0xFE000000,
0x01000000,
FULL_ACCS};
// ACPI
static STM_RSC_IO_DESC rsc_pm_io = {{IO_RANGE, sizeof(STM_RSC_IO_DESC)}, 0, 128};
// PCIE MMIO
static STM_RSC_MMIO_DESC rsc_pcie_mmio = {{MMIO_RANGE, sizeof(STM_RSC_MMIO_DESC)},
0,
0, // Length
RDWR_ACCS};
// Local APIC
static STM_RSC_MMIO_DESC rsc_apic_mmio = {{MMIO_RANGE, sizeof(STM_RSC_MMIO_DESC)},
0,
0x400,
RDWR_ACCS};
// Software SMI
static STM_RSC_TRAPPED_IO_DESC rsc_sw_smi_trap_io = {
{TRAPPED_IO_RANGE, sizeof(STM_RSC_TRAPPED_IO_DESC)},
0xB2,
2};
// End of list
static STM_RSC_END rsc_list_end __attribute__((used)) = {
{END_OF_RESOURCES, sizeof(STM_RSC_END)}, 0};
// Common PCI devices
//
// LPC bridge
STM_RSC_PCI_CFG_DESC rsc_lpc_bridge_pci = {
{PCI_CFG_RANGE, sizeof(STM_RSC_PCI_CFG_DESC)},
RDWR_ACCS,
0,
0,
0x1000,
0,
0,
{
{1, 1, sizeof(STM_PCI_DEVICE_PATH_NODE), LPC_FUNCTION,
LPC_DEVICE},
},
};
// Template for MSR resources.
STM_RSC_MSR_DESC rsc_msr_tpl = {
{MACHINE_SPECIFIC_REG, sizeof(STM_RSC_MSR_DESC)},
};
// MSR indices to register
typedef struct {
uint32_t msr_index;
uint64_t read_mask;
uint64_t write_mask;
} MSR_TABLE_ENTRY;
MSR_TABLE_ENTRY msr_table[] = {
// Index Read Write
// MASK64 means need access, MASK0 means no need access.
{SMRR_PHYSBASE_MSR, MASK64, MASK0},
{SMRR_PHYSMASK_MSR, MASK64, MASK0},
};
/*
* Fix up PCIE resource.
*/
static void fixup_pciex_resource(void)
{
// Find max bus number and PCIEX length
rsc_pcie_mmio.length = CONFIG_SA_PCIEX_LENGTH; // 0x10000000;// 256 MB
rsc_pcie_mmio.base = CONFIG_MMCONF_BASE_ADDRESS;
}
/*
* Add basic resources to BIOS resource database.
*/
static void add_simple_resources(void)
{
int Status = 0;
msr_t ReadMsr;
ReadMsr = rdmsr(SMRR_PHYSBASE_MSR);
rsc_tseg_memory.base = ReadMsr.lo & 0xFFFFF000;
ReadMsr = rdmsr(SMRR_PHYSMASK_MSR);
rsc_tseg_memory.length = (~(ReadMsr.lo & 0xFFFFF000) + 1);
rsc_pm_io.base = (uint16_t)get_pmbase();
// Local APIC. We assume that all thteads are programmed identically
// despite that it is possible to have individual APIC address for
// each of the threads. If this is the case this programming should
// be corrected.
ReadMsr = rdmsr(IA32_APIC_BASE_MSR_INDEX);
rsc_apic_mmio.base = ((uint64_t)ReadMsr.lo & 0xFFFFF000) |
((uint64_t)(ReadMsr.hi & 0x0000000F) << 32);
// PCIEX BAR
fixup_pciex_resource();
Status |= add_pi_resource((void *)&rsc_tseg_memory, 1);
Status |= add_pi_resource((void *)&rsc_spi_memory, 1);
Status |= add_pi_resource((void *)&rsc_pm_io, 1);
Status |= add_pi_resource((void *)&rsc_pcie_mmio, 1);
Status |= add_pi_resource((void *)&rsc_apic_mmio, 1);
Status |= add_pi_resource((void *)&rsc_sw_smi_trap_io, 1);
Status |= add_pi_resource((void *)&rsc_lpc_bridge_pci, 1);
if (Status != 0)
printk(BIOS_DEBUG, "STM - Error in adding simple resources\n");
}
/*
* Add MSR resources to BIOS resource database.
*/
static void add_msr_resources(void)
{
uint32_t Status = 0;
uint32_t Index;
for (Index = 0; Index < ARRAY_SIZE(msr_table); Index++) {
rsc_msr_tpl.msr_index = (uint32_t)msr_table[Index].msr_index;
rsc_msr_tpl.read_mask = (uint64_t)msr_table[Index].read_mask;
rsc_msr_tpl.write_mask = (uint64_t)msr_table[Index].write_mask;
Status |= add_pi_resource((void *)&rsc_msr_tpl, 1);
}
if (Status != 0)
printk(BIOS_DEBUG, "STM - Error in adding MSR resources\n");
}
/*
* Add resources to BIOS resource database.
*/
extern uint8_t *m_stm_resources_ptr;
void add_resources_cmd(void)
{
m_stm_resources_ptr = NULL;
add_simple_resources();
add_msr_resources();
}

View file

@ -0,0 +1,32 @@
/* @file
* STM platform SMM resource
*
* Copyright (c) 2015, Intel Corporation. All rights reserved.
* This program and the accompanying materials are licensed and made available
* under the terms and conditions of the BSD License which accompanies this
* distribution. The full text of the license may be found at
* http://opensource.org/licenses/bsd-license.php.
*
* THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
* WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR
* IMPLIED.
*/
#ifndef _STM_PLATFORM_RESOURCE_H_
#define _STM_PLATFORM_RESOURCE_H_
#define MASK0 0
#define MASK64 0xFFFFFFFFFFFFFFFFull
// LPC
#define LPC_DEVICE 31
#define LPC_FUNCTION 0
#define R_ACPI_PM_BASE 0x40
#define ACPI_PM_BASE_MASK 0xFFF8
/*
* Add resources to BIOS resource database.
*/
void add_resources_cmd(void);
#endif

View file

@ -0,0 +1,213 @@
/* @file
* STM platform SMM API
*
* Copyright (c) 2015, Intel Corporation. All rights reserved.
* This program and the accompanying materials are licensed and made
* available under the terms and conditions of the BSD License which
* accompanies this distribution. The full text of the license may be found
* at http://opensource.org/licenses/bsd-license.php.
*
* THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
* WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR
* IMPLIED.
*
*/
#include <security/intel/stm/StmApi.h>
#include <security/intel/stm/SmmStm.h>
#include <security/intel/stm/StmPlatformResource.h>
#include <security/tpm/tspi.h>
#include <cpu/x86/smm.h>
#include <cpu/x86/msr.h>
#include <stddef.h>
#include <cbfs.h>
#include <console/console.h>
#include <lib.h>
#include <stdint.h>
#include <arch/rom_segs.h>
/*
* Load STM image to MSEG
*
* @retval SUCCESS STM is loaded to MSEG
*/
int load_stm_image(uintptr_t mseg)
{
int status;
void *mseg_base;
uint32_t stm_buffer_size;
uint32_t stm_image_size;
bool stm_status;
STM_HEADER *stm_header;
// Extract STM image from FV
mseg_base = (void *)mseg;
stm_buffer_size = CONFIG_MSEG_SIZE;
stm_image_size = 0;
memset((void *)mseg_base, 0, CONFIG_MSEG_SIZE); // clear the mseg
stm_image_size = cbfs_boot_load_file("stm.bin", mseg_base,
stm_buffer_size, CBFS_TYPE_RAW);
printk(BIOS_DEBUG, "STM:loaded into mseg: 0x%p size: %u\n", mseg_base,
stm_image_size);
/* status is number of bytes loaded */
stm_status = stm_check_stm_image(mseg_base, stm_image_size);
if (!stm_status) {
printk(BIOS_DEBUG, "STM: Error in STM image\n");
return -1;
}
stm_header = mseg_base;
stm_gen_4g_pagetable_x64((uint32_t)mseg_base
+ stm_header->hw_stm_hdr.cr3_offset);
// Debug stuff
printk(BIOS_DEBUG,
"STM: Header-Revision %d Features 0x%08x Cr3Offset 0x%08x\n",
stm_header->hw_stm_hdr.stm_header_revision,
stm_header->hw_stm_hdr.monitor_features,
stm_header->hw_stm_hdr.cr3_offset);
printk(BIOS_DEBUG,
"STM: Header-StaticImageSize: %d Cr3Location: 0x%08x\n",
stm_header->sw_stm_hdr.static_image_size,
((uint32_t)mseg_base + stm_header->hw_stm_hdr.cr3_offset));
status = 0; // always return good for now
return status;
}
struct descriptor {
uint16_t limit;
uintptr_t base;
} __attribute__((packed));
static void read_gdtr(struct descriptor *gdtr)
{
__asm__ __volatile__("sgdt %0" : "=m"(*gdtr));
}
void setup_smm_descriptor(void *smbase, void *base_smbase, int32_t apic_id,
int32_t entry32_off)
{
struct descriptor gdtr;
void *smbase_processor;
//msr_t smbase_msr;
TXT_PROCESSOR_SMM_DESCRIPTOR *psd;
smbase_processor = (void *) SMM_DEFAULT_BASE;//we are here
psd = smbase + SMM_PSD_OFFSET;
printk(BIOS_DEBUG,
"STM: Smm Descriptor setup: Smbase: %p Smbase_processor: %p Psd: %p\n",
smbase,
smbase_processor,
psd);
memset(psd, 0, sizeof(TXT_PROCESSOR_SMM_DESCRIPTOR));
memcpy(&psd->signature, TXT_PROCESSOR_SMM_DESCRIPTOR_SIGNATURE, 8);
psd->smm_descriptor_ver_major =
TXT_PROCESSOR_SMM_DESCRIPTOR_VERSION_MAJOR;
psd->smm_descriptor_ver_minor =
TXT_PROCESSOR_SMM_DESCRIPTOR_VERSION_MINOR;
psd->smm_smi_handler_rip =
(uint64_t)((uintptr_t)base_smbase + SMM_ENTRY_OFFSET +
entry32_off);
psd->local_apic_id = apic_id;
psd->size = sizeof(TXT_PROCESSOR_SMM_DESCRIPTOR);
psd->acpi_rsdp = 0;
psd->bios_hw_resource_requirements_ptr =
(uint64_t)((uintptr_t)get_stm_resource());
psd->smm_cs = ROM_CODE_SEG;
psd->smm_ds = ROM_DATA_SEG;
psd->smm_ss = ROM_DATA_SEG;
psd->smm_other_segment = ROM_DATA_SEG;
psd->smm_tr = SMM_TASK_STATE_SEG;
// At this point the coreboot smm_stub is relative to the default
// smbase and not the one for the smi handler in tseg. So we have
// to adjust the gdtr.base
read_gdtr(&gdtr);
gdtr.base -= (uintptr_t) smbase_processor;
gdtr.base += (uintptr_t) base_smbase;
psd->smm_gdt_ptr = gdtr.base;
psd->smm_gdt_size = gdtr.limit + 1; // the stm will subtract, so add
printk(BIOS_DEBUG, "STM: Smm Descriptor setup complete - Smbase: %p Psd: %p\n",
smbase, psd);
}
extern uint8_t *stm_resource_heap;
#define FXSAVE_SIZE 512
static int stm_load_status = 0;
void stm_setup(uintptr_t mseg, int cpu, int num_cpus, uintptr_t smbase,
uintptr_t base_smbase, uint32_t offset32)
{
msr_t InitMseg;
msr_t MsegChk;
msr_t vmx_basic;
uintptr_t addr_calc; // used to calculate the stm resource heap area
printk(BIOS_DEBUG, "STM: set up for cpu %d/%d\n", cpu, num_cpus);
vmx_basic = rdmsr(IA32_VMX_BASIC_MSR);
// Does this processor support an STM?
if ((vmx_basic.hi & VMX_BASIC_HI_DUAL_MONITOR) != VMX_BASIC_HI_DUAL_MONITOR) {
printk(BIOS_WARNING, "STM: not supported on CPU %d\n", cpu);
return;
}
// This code moved here because paralled SMM setup can cause some
// processors to get a bad value.
addr_calc = mseg - CONFIG_BIOS_RESOURCE_LIST_SIZE;
stm_resource_heap = (uint8_t *) addr_calc;
if (cpu == 0) {
// need to create the BIOS resource list once
// first calculate the location in SMRAM
printk(BIOS_DEBUG, "STM: stm_resource_heap located at %p\n",
stm_resource_heap);
//setup the the list
add_resources_cmd();
stm_load_status = load_stm_image(mseg);
}
if (stm_load_status == 0) {
// enable STM for this cpu
InitMseg.lo = mseg | IA32_SMM_MONITOR_VALID;
InitMseg.hi = 0;
wrmsr(IA32_SMM_MONITOR_CTL_MSR, InitMseg);
MsegChk = rdmsr(IA32_SMM_MONITOR_CTL_MSR);
printk(BIOS_DEBUG, "STM: MSEG Initialized (%d) 0x%08x 0x%08x\n",
cpu, MsegChk.hi, MsegChk.lo);
// setup the descriptor for this cpu
setup_smm_descriptor((void *)smbase, (void *) base_smbase,
cpu, offset32);
} else {
printk(BIOS_DEBUG,
"STM: Error in STM load, STM not enabled: %d\n",
cpu);
}
}

View file

@ -26,14 +26,12 @@ config INTEL_TXT
if INTEL_TXT
menu "Intel"
config INTEL_TXT_BIOSACM_FILE
string "BIOS ACM file"
default "3rdparty/blobs/soc/intel/fsp_broadwell_de/biosacm.bin" if SOC_INTEL_FSP_BROADWELL_DE
default "3rdparty/blobs/soc/intel/skylake/biosacm.bin" if SOC_INTEL_COMMON_SKYLAKE_BASE
help
Intel TXT BIOS ACM file. This file can be obtained by privileged
Intel TXT BIOS ACM file. This file can be obtained through privileged
access to Intel resources. Or for some platforms found inside the
blob repository.
@ -42,17 +40,33 @@ config INTEL_TXT_SINITACM_FILE
default "3rdparty/blobs/soc/intel/fsp_broadwell_de/sinitacm.bin" if SOC_INTEL_FSP_BROADWELL_DE
default "3rdparty/blobs/soc/intel/skylake/sinitacm.bin" if SOC_INTEL_COMMON_SKYLAKE_BASE
help
Intel TXT SINIT ACM file. This file can be obtained by privileged
Intel TXT SINIT ACM file. This file can be obtained through privileged
access to Intel resources. Or for some platforms found inside the
blob repository.
config INTEL_TXT_LOGGING
bool "Enable verbose logging"
help
Print more TXT related debug output.
Use in pre-production environments only!
config INTEL_TXT_BIOSACM_ALIGNMENT
hex
default 0x20000 # 128KB
default 0x20000 # 128 KiB
help
Exceptions are Ivy- and Sandy Bridge with 64KB and Purely with 256KB
alignment size. Please overwrite it SoC specific.
Exceptions are Ivy and Sandy Bridge with 64 KiB and Purley with 256 KiB
alignment size. If necessary, override from platform-specific Kconfig.
endmenu # Intel
config INTEL_TXT_CBFS_BIOS_POLICY
string
default "txt_bios_policy.bin"
config INTEL_TXT_CBFS_BIOS_ACM
string
default "txt_bios_acm.bin"
config INTEL_TXT_CBFS_SINIT_ACM
string
default "txt_sinit_acm.bin"
endif

View file

@ -1,5 +1,14 @@
ifeq ($(CONFIG_INTEL_TXT),y)
romstage-y += common.c
romstage-$(CONFIG_INTEL_TXT_LOGGING) += logging.c
ramstage-y += common.c
ramstage-y += getsec.c
ramstage-y += getsec_enteraccs.S
ramstage-y += ramstage.c
ramstage-$(CONFIG_INTEL_TXT_LOGGING) += logging.c
cbfs-files-y += txt_bios_acm.bin
txt_bios_acm.bin-file := $(CONFIG_INTEL_TXT_BIOSACM_FILE)
txt_bios_acm.bin-type := raw
@ -13,6 +22,8 @@ txt_sinit_acm.bin-align := 0x10
txt_sinit_acm.bin-compression := lzma
endif
ifeq ($(CONFIG_CPU_INTEL_FIRMWARE_INTERFACE_TABLE),y)
INTERMEDIATE+=add_acm_fit
add_acm_fit: $(obj)/coreboot.pre $(IFITTOOL)
$(IFITTOOL) -r COREBOOT -a -n txt_bios_acm.bin -t 2 -s $(CONFIG_CPU_INTEL_NUM_FIT_ENTRIES) -f $<
@ -26,7 +37,9 @@ ibb-files += bootblock
INTERMEDIATE+=add_ibb_fit
add_ibb_fit: $(obj)/coreboot.pre $(IFITTOOL)
$(foreach file, $(ibb-files), $(shell $(IFITTOOL) -f $< -a -n $(file) -t 7 -s $(CONFIG_CPU_INTEL_NUM_FIT_ENTRIES) \
-r COREBOOT)) true
$(foreach file, $(ibb-files), $(shell $(IFITTOOL) -f $< -a -n $(file) -t 7 \
-s $(CONFIG_CPU_INTEL_NUM_FIT_ENTRIES) -r COREBOOT)) true
endif
endif # CPU_INTEL_FIRMWARE_INTERFACE_TABLE
endif # INTEL_TXT

View file

@ -0,0 +1,421 @@
/* SPDX-License-Identifier: GPL-2.0-only */
#include <arch/mmio.h>
#include <string.h>
#include <console/console.h>
#include <types.h>
#include <cbfs.h>
#include <cpu/x86/lapic.h>
#include <cpu/x86/cr.h>
#include <cpu/x86/mp.h>
#include <lib.h>
#include <smp/node.h>
#include <cf9_reset.h>
#include "txt.h"
#include "txt_register.h"
#include "txt_getsec.h"
/**
* Dump the ACM error status bits.
*
* @param acm_error The status register to dump
* @return -1 on error (register is not valid)
* 0 on error (Class > 0 and Major > 0)
* 1 on success (Class == 0 and Major == 0 and progress > 0)
*/
int intel_txt_log_acm_error(const uint32_t acm_error)
{
if (!(acm_error & ACMERROR_TXT_VALID))
return -1;
const uint8_t type = (acm_error & ACMERROR_TXT_TYPE_CODE)
>> ACMERROR_TXT_TYPE_SHIFT;
switch (type) {
case ACMERROR_TXT_AC_MODULE_TYPE_BIOS:
printk(BIOS_ERR, "BIOSACM");
break;
case ACMERROR_TXT_AC_MODULE_TYPE_SINIT:
printk(BIOS_ERR, "SINIT");
break;
default:
printk(BIOS_ERR, "ACM");
break;
}
printk(BIOS_ERR, ": Error code valid\n");
if (acm_error & ACMERROR_TXT_EXTERNAL)
printk(BIOS_ERR, " Caused by: External\n");
else
printk(BIOS_ERR, " Caused by: Processor\n");
const uint32_t class = (acm_error & ACMERROR_TXT_CLASS_CODE)
>> ACMERROR_TXT_CLASS_SHIFT;
const uint32_t major = (acm_error & ACMERROR_TXT_MAJOR_CODE)
>> ACMERROR_TXT_MAJOR_SHIFT;
const uint32_t minor = (acm_error & ACMERROR_TXT_MINOR_CODE)
>> ACMERROR_TXT_MINOR_SHIFT;
const uint32_t progress = (acm_error & ACMERROR_TXT_PROGRESS_CODE)
>> ACMERROR_TXT_PROGRESS_SHIFT;
if (!minor) {
if (class == 0 && major == 0 && progress > 0) {
printk(BIOS_ERR, " Execution successful\n");
printk(BIOS_ERR, " Progress code 0x%x\n", progress);
} else {
printk(BIOS_ERR, " Error Class: %x\n", class);
printk(BIOS_ERR, " Error: %x.%x\n", major, progress);
}
} else {
printk(BIOS_ERR, " ACM didn't start\n");
printk(BIOS_ERR, " Error Type: 0x%x\n", acm_error & 0xffffff);
return -1;
}
return (acm_error & ACMERROR_TXT_EXTERNAL) && class == 0 && major == 0 && progress > 0;
}
void intel_txt_log_spad(void)
{
const uint64_t acm_status = read64((void *)TXT_SPAD);
printk(BIOS_INFO, "TXT-STS: ACM verification ");
if (acm_status & ACMSTS_VERIFICATION_ERROR)
printk(BIOS_INFO, "error\n");
else
printk(BIOS_INFO, "successful\n");
printk(BIOS_INFO, "TXT-STS: IBB ");
if (acm_status & ACMSTS_IBB_MEASURED)
printk(BIOS_INFO, "measured\n");
else
printk(BIOS_INFO, "not measured\n");
printk(BIOS_INFO, "TXT-STS: TXT is ");
if (acm_status & ACMSTS_TXT_DISABLED)
printk(BIOS_INFO, "disabled\n");
else
printk(BIOS_INFO, "not disabled\n");
printk(BIOS_INFO, "TXT-STS: BIOS is ");
if (acm_status & ACMSTS_BIOS_TRUSTED)
printk(BIOS_INFO, "trusted\n");
else
printk(BIOS_INFO, "not trusted\n");
}
/* Returns true if secrets might be in memory */
bool intel_txt_memory_has_secrets(void)
{
bool ret;
if (!CONFIG(INTEL_TXT))
return false;
ret = (read8((void *)TXT_ESTS) & TXT_ESTS_WAKE_ERROR_STS) ||
(read64((void *)TXT_E2STS) & TXT_E2STS_SECRET_STS);
if (ret)
printk(BIOS_CRIT, "TXT-STS: Secrets in memory!\n");
return ret;
}
static struct acm_info_table *find_info_table(const void *ptr)
{
const struct acm_header_v0 *acm_header = (struct acm_header_v0 *)ptr;
return (struct acm_info_table *)(ptr +
(acm_header->header_len + acm_header->scratch_size) * sizeof(uint32_t));
}
/**
* Validate that the provided ACM is useable on this platform.
*/
static int validate_acm(const void *ptr)
{
const struct acm_header_v0 *acm_header = (struct acm_header_v0 *)ptr;
uint32_t max_size_acm_area = 0;
if (acm_header->module_type != CHIPSET_ACM)
return ACM_E_TYPE_NOT_MATCH;
/* Seems inconsistent across generations. */
if (acm_header->module_sub_type != 0 && acm_header->module_sub_type != 1)
return ACM_E_MODULE_SUB_TYPE_WRONG;
if (acm_header->module_vendor != INTEL_ACM_VENDOR)
return ACM_E_MODULE_VENDOR_NOT_INTEL;
if (((acm_header->header_len + acm_header->scratch_size) * sizeof(uint32_t) +
sizeof(struct acm_info_table)) > (acm_header->size & 0xffffff) * sizeof(uint32_t)) {
return ACM_E_SIZE_INCORRECT;
}
if (!getsec_parameter(NULL, NULL, &max_size_acm_area, NULL, NULL, NULL))
return ACM_E_CANT_CALL_GETSEC;
/*
* Causes #GP if acm_header->size > processor internal authenticated
* code area capacity.
* SAFER MODE EXTENSIONS REFERENCE.
* Intel 64 and IA-32 Architectures Software Developer Manuals Vol 2D
*/
const size_t acm_len = 1UL << log2_ceil((acm_header->size & 0xffffff) << 2);
if (max_size_acm_area < acm_len) {
printk(BIOS_ERR, "TEE-TXT: BIOS ACM doesn't fit into AC execution region\n");
return ACM_E_NOT_FIT_INTO_CPU_ACM_MEM;
}
struct acm_info_table *info = find_info_table(ptr);
if (!info)
return ACM_E_NO_INFO_TABLE;
if (info->chipset_acm_type != BIOS)
return ACM_E_NOT_BIOS_ACM;
static const u8 acm_uuid[] = {
0xaa, 0x3a, 0xc0, 0x7f, 0xa7, 0x46, 0xdb, 0x18,
0x2e, 0xac, 0x69, 0x8f, 0x8d, 0x41, 0x7f, 0x5a,
};
if (memcmp(acm_uuid, info->uuid, sizeof(acm_uuid)) != 0)
return ACM_E_UUID_NOT_MATCH;
if ((acm_header->flags & ACM_FORMAT_FLAGS_DEBUG) ==
(read64((void *)TXT_VER_FSBIF) & TXT_VER_PRODUCTION_FUSED))
return ACM_E_PLATFORM_IS_NOT_PROD;
return 0;
}
/*
* Test all bits for TXT execution.
*
* @return 0 on success
*/
int intel_txt_run_bios_acm(const u8 input_params)
{
struct cbfsf file;
void *acm_data;
struct region_device acm;
size_t acm_len;
int ret;
if (cbfs_boot_locate(&file, CONFIG_INTEL_TXT_CBFS_BIOS_ACM, NULL)) {
printk(BIOS_ERR, "TEE-TXT: Couldn't locate BIOS ACM in CBFS.\n");
return -1;
}
cbfs_file_data(&acm, &file);
acm_data = rdev_mmap_full(&acm);
acm_len = region_device_sz(&acm);
if (!acm_data || acm_len == 0) {
printk(BIOS_ERR, "TEE-TXT: Couldn't map BIOS ACM from CBFS.\n");
return -1;
}
/*
* CPU enforces only 4KiB alignment.
* Chapter A.1.1
* Intel TXT Software Development Guide (Document: 315168-015)
*/
if (!IS_ALIGNED((uintptr_t)acm_data, 4096)) {
printk(BIOS_ERR, "TEE-TXT: BIOS ACM isn't mapped at page boundary.\n");
rdev_munmap(&acm, acm_data);
return -1;
}
/*
* Causes #GP if not multiple of 64.
* SAFER MODE EXTENSIONS REFERENCE.
* Intel 64 and IA-32 Architectures Software Developer Manuals Vol 2D
*/
if (!IS_ALIGNED(acm_len, 64)) {
printk(BIOS_ERR, "TEE-TXT: BIOS ACM size isn't multiple of 64.\n");
rdev_munmap(&acm, acm_data);
return -1;
}
/*
* The ACM should be aligned to it's size, but that's not possible, as
* some ACMs are not power of two. Use the next power of two for verification.
*/
if (!IS_ALIGNED((uintptr_t)acm_data, (1UL << log2_ceil(acm_len)))) {
printk(BIOS_ERR, "TEE-TXT: BIOS ACM isn't aligned to its size.\n");
rdev_munmap(&acm, acm_data);
return -1;
}
if (CONFIG(INTEL_TXT_LOGGING))
txt_dump_acm_info(acm_data);
ret = validate_acm(acm_data);
if (ret < 0) {
printk(BIOS_ERR, "TEE-TXT: Validation of ACM failed with: %d\n", ret);
rdev_munmap(&acm, acm_data);
return ret;
}
/* Call into assembly which invokes the referenced ACM */
getsec_enteraccs(input_params, (uintptr_t)acm_data, acm_len);
rdev_munmap(&acm, acm_data);
const uint64_t acm_status = read64((void *)TXT_SPAD);
if (acm_status & ACMERROR_TXT_VALID) {
printk(BIOS_ERR, "TEE-TXT: FATAL ACM launch error !\n");
/*
* WARNING !
* To clear TXT.BIOSACM.ERRORCODE you must issue a cold reboot!
*/
intel_txt_log_acm_error(read32((void *)TXT_BIOSACM_ERRORCODE));
return -1;
}
if (intel_txt_log_acm_error(read32((void *)TXT_BIOSACM_ERRORCODE)) != 1)
return -1;
return 0;
}
/* Returns true if cond is not met */
static bool check_precondition(const int cond)
{
printk(BIOS_DEBUG, "%s\n", cond ? "true" : "false");
return !cond;
}
/*
* Test all bits that are required for Intel TXT.
* Enable SMX if available.
*
* @return 0 on success
*/
bool intel_txt_prepare_txt_env(void)
{
bool failure = false;
uint32_t txt_feature_flags = 0;
unsigned int ecx = cpuid_ecx(1);
printk(BIOS_DEBUG, "TEE-TXT: CPU supports SMX: ");
failure |= check_precondition(ecx & CPUID_SMX);
printk(BIOS_DEBUG, "TEE-TXT: CPU supports VMX: ");
failure |= check_precondition(ecx & CPUID_VMX);
msr_t msr = rdmsr(IA32_FEATURE_CONTROL);
if (!(msr.lo & BIT(0))) {
printk(BIOS_ERR, "TEE-TXT: IA32_FEATURE_CONTROL is not locked\n");
full_reset();
}
printk(BIOS_DEBUG, "TEE-TXT: IA32_FEATURE_CONTROL\n");
printk(BIOS_DEBUG, " VMXON in SMX enable: ");
failure |= check_precondition(msr.lo & BIT(1));
printk(BIOS_DEBUG, " VMXON outside SMX enable: ");
failure |= check_precondition(msr.lo & FEATURE_ENABLE_VMX);
printk(BIOS_DEBUG, " register is locked: ");
failure |= check_precondition(msr.lo & BIT(0));
/* IA32_FEATURE_CONTROL enables getsec instructions */
printk(BIOS_DEBUG, " GETSEC (all instructions) is enabled: ");
failure |= check_precondition((msr.lo & 0xff00) == 0xff00);
/* Prevent crash and opt out early */
if (failure)
return true;
uint32_t eax = 0;
/*
* GetSec[CAPABILITIES]
* SAFER MODE EXTENSIONS REFERENCE.
* Intel 64 and IA-32 Architectures Software Developer Manuals Vol 2D
* Must check BIT0 of TXT chipset has been detected by CPU.
*/
if (!getsec_capabilities(&eax))
return true;
printk(BIOS_DEBUG, "TEE-TXT: GETSEC[CAPABILITIES] returned:\n");
printk(BIOS_DEBUG, " TXT capable chipset: %s\n", (eax & BIT(0)) ? "true" : "false");
printk(BIOS_DEBUG, " ENTERACCS available: %s\n", (eax & BIT(2)) ? "true" : "false");
printk(BIOS_DEBUG, " EXITAC available: %s\n", (eax & BIT(3)) ? "true" : "false");
printk(BIOS_DEBUG, " SENTER available: %s\n", (eax & BIT(4)) ? "true" : "false");
printk(BIOS_DEBUG, " SEXIT available: %s\n", (eax & BIT(5)) ? "true" : "false");
printk(BIOS_DEBUG, " PARAMETERS available: %s\n", (eax & BIT(6)) ? "true" : "false");
/*
* Causes #GP if function is not supported by getsec.
* SAFER MODE EXTENSIONS REFERENCE.
* Intel 64 and IA-32 Architectures Software Developer Manuals Vol 2D
* Order Number: 325383-060US
*/
if ((eax & 0x7d) != 0x7d)
failure = true;
const uint64_t status = read64((void *)TXT_SPAD);
if (status & ACMSTS_TXT_DISABLED) {
printk(BIOS_INFO, "TEE-TXT: TXT disabled by BIOS policy in FIT.\n");
failure = true;
}
/*
* Only the BSP must call getsec[ENTERACCS].
* SAFER MODE EXTENSIONS REFERENCE.
* Intel 64 and IA-32 Architectures Software Developer Manuals Vol 2D
* Order Number: 325383-060US
*/
if (!boot_cpu()) {
printk(BIOS_ERR, "TEE-TXT: BSP flag not set in APICBASE_MSR.\n");
failure = true;
}
/*
* There must be no MCEs pending.
* Intel 64 and IA-32 Architectures Software Developer Manuals Vol 2D
* Order Number: 325383-060US
*/
msr = rdmsr(IA32_MCG_STATUS);
if (msr.lo & 0x4) {
printk(BIOS_ERR, "TEE-TXT: IA32_MCG_STATUS.MCIP is set.\n");
failure = true;
}
if (!getsec_parameter(NULL, NULL, NULL, NULL, NULL, &txt_feature_flags)) {
return true;
} else {
printk(BIOS_DEBUG, "TEE-TXT: Machine Check Register: ");
if (txt_feature_flags & GETSEC_PARAMS_TXT_EXT_MACHINE_CHECK)
printk(BIOS_DEBUG, "preserved\n");
else
printk(BIOS_DEBUG, "must be clear\n");
}
if (!(txt_feature_flags & GETSEC_PARAMS_TXT_EXT_MACHINE_CHECK)) {
/*
* Make sure there are no uncorrectable MCE errors.
* Intel 64 and IA-32 Architectures Software Developer Manuals Vol 2D
*/
msr = rdmsr(IA32_MCG_CAP);
size_t max_mc_msr = msr.lo & MCA_BANKS_MASK;
for (size_t i = 0; i < max_mc_msr; i++) {
msr = rdmsr(IA32_MC0_STATUS + 4 * i);
if (!(msr.hi & MCA_STATUS_HI_UC))
continue;
printk(BIOS_ERR, "TEE-TXT: IA32_MC%zd_STATUS.UC is set.\n", i);
failure = true;
break;
}
}
/* Need to park all APs. */
if (CONFIG(PARALLEL_MP_AP_WORK))
mp_park_aps();
return failure;
}

View file

@ -0,0 +1,117 @@
/* SPDX-License-Identifier: GPL-2.0-only */
#include <stdint.h>
#include <cpu/x86/lapic.h>
#include <cpu/x86/cr.h>
#include <cpu/x86/cache.h>
#include <cpu/x86/mp.h>
#include "txt_register.h"
#include "txt_getsec.h"
/**
* Check for SMX support and enable it if possible.
*
* Returns false on error, true on success.
*/
static bool getsec_enabled(void)
{
unsigned int ecx = cpuid_ecx(1);
/*
* Check if SMX and VMX is supported by CPU.
*/
if (!(ecx & CPUID_SMX) || !(ecx & CPUID_VMX))
return false;
/*
* Check if SMX, VMX and GetSec instructions haven't been disabled.
*/
msr_t msr = rdmsr(IA32_FEATURE_CONTROL);
if ((msr.lo & 0xff07) != 0xff07)
return false;
/*
* Enable SMX. Required to execute GetSec instruction.
* Chapter 2.2.4.3
* Intel TXT Software Development Guide (Document: 315168-015)
*/
write_cr4(read_cr4() | CR4_SMXE);
return true;
}
/**
* Get information as returned by getsec[PARAMETER].
* Arguments can be set to NULL if not needed.
*
* Returns false on error, true on success.
*/
bool getsec_parameter(uint32_t *version_mask,
uint32_t *version_numbers_supported,
uint32_t *max_size_acm_area,
uint32_t *memory_type_mask,
uint32_t *senter_function_disable,
uint32_t *txt_feature_flags)
{
uint32_t i, eax, ebx, ecx;
if (!getsec_enabled())
return false;
/*
* SAFER MODE EXTENSIONS REFERENCE.
* Intel 64 and IA-32 Architectures Software Developer Manuals Vol 2D
*/
for (i = 0; i < 0x1f; i++) {
/* Getsec[PARAMETERS] */
asm volatile ("getsec\n"
: "=a" (eax), "=b" (ebx), "=c" (ecx)
: "a" (IA32_GETSEC_PARAMETERS), "b" (i) :);
switch (eax & 0x1f) {
case 0: /* NULL - Exit marker */
return true;
case 1: /* Supported AC module versions */
if (version_mask)
*version_mask = ebx;
if (version_numbers_supported)
*version_numbers_supported = ecx;
break;
case 2: /* Max size of authenticated code execution area */
if (max_size_acm_area)
*max_size_acm_area = eax & ~0x1f;
break;
case 3: /* External memory types supported during AC mode */
if (memory_type_mask)
*memory_type_mask = eax;
break;
case 4: /* Selective SENTER functionality control */
if (senter_function_disable)
*senter_function_disable = eax & (0x3f00);
break;
case 5: /* TXT extensions support */
if (txt_feature_flags)
*txt_feature_flags = eax & (0x60);
break;
}
}
return true;
}
/**
* Get capabilities as returned by getsec[CAPABILITIES].
*
* Returns false on error, true on success.
*/
bool getsec_capabilities(uint32_t *eax)
{
if (!getsec_enabled())
return false;
asm volatile ("getsec\n"
: "=a" (*eax)
: "a" (IA32_GETSEC_CAPABILITIES), "b" (0) :);
return true;
}

View file

@ -0,0 +1,318 @@
/* SPDX-License-Identifier: GPL-2.0-only */
#include <cpu/x86/mtrr.h>
#include <cpu/x86/cr.h>
#include <cpu/x86/msr.h>
#define MTRR_HIGH_MASK $((1 << (CONFIG_CPU_ADDR_BITS - 32)) - 1)
.macro PUSH_MSR x
movl $(\x), %ecx
rdmsr
push %eax
push %edx
.endm
.macro POP_MSR x
movl $(\x), %ecx
pop %edx
pop %eax
wrmsr
.endm
.macro CLEAR_MSR x
movl $(\x), %ecx
xorl %edx, %edx
xorl %eax, %eax
wrmsr
.endm
.align 4
.text
/*
* See "SAFER MODE EXTENSIONS REFERENCE."
* Chapter "GETSEC[ENTERACCS] - Execute Authenticated Chipset Code" for reference.
* Intel 64 and IA-32 Architectures Software Developer Manuals Vol 2D
*
* void getsec_enteraccs(uint32_t esi,
* uint32_t acm_base,
* uint32_t acm_size);
*/
.global getsec_enteraccs
getsec_enteraccs:
/* Backup current register state */
pushl %ebp
movl %esp, %ebp
pushal
movl %cr0, %eax
pushl %eax
movl %cr4, %eax
pushl %eax
/* Pushed 10 32bit registers */
/* Reserve space on stack for GDT */
subl $8, %esp
PUSH_MSR IA32_MISC_ENABLE
PUSH_MSR MTRR_FIX_64K_00000
PUSH_MSR MTRR_FIX_16K_80000
PUSH_MSR MTRR_FIX_16K_A0000
PUSH_MSR MTRR_FIX_4K_C0000
PUSH_MSR MTRR_FIX_4K_C8000
PUSH_MSR MTRR_FIX_4K_D0000
PUSH_MSR MTRR_FIX_4K_D8000
PUSH_MSR MTRR_FIX_4K_E0000
PUSH_MSR MTRR_FIX_4K_F0000
PUSH_MSR MTRR_FIX_4K_F8000
/* Push variable MTRRs in ascending order */
xorl %ebx, %ebx
jmp cond_push_var_mtrrs
body_push_var_mtrrs:
movl %ebx, %ecx
shll %ecx
addl $(MTRR_PHYS_BASE(0)), %ecx
rdmsr
push %eax
push %edx
incl %ecx /* MTRR_PHYS_MASK */
rdmsr
push %eax
push %edx
incl %ebx
cond_push_var_mtrrs:
movl $(MTRR_CAP_MSR), %ecx
rdmsr
andl $(0xff), %eax
cmp %ebx, %eax
jg body_push_var_mtrrs
/*
* Disable cache.
* Chapter 2.2.4.3
* Intel TXT Software Development Guide (Document: 315168-015)
*/
movl %cr0, %eax
orl $(CR0_CD | CR0_NW), %eax
movl %eax, %cr0
/* Disable fixed MTRRs */
movl $(MTRR_DEF_TYPE_MSR), %ecx
rdmsr
andl $(~MTRR_DEF_TYPE_FIX_EN), %eax
wrmsr
/*
* Clear fixed MTRRs.
* Chapter 2.2.5.1
* Intel TXT Software Development Guide (Document: 315168-015)
*/
CLEAR_MSR MTRR_FIX_64K_00000
CLEAR_MSR MTRR_FIX_16K_80000
CLEAR_MSR MTRR_FIX_16K_A0000
CLEAR_MSR MTRR_FIX_4K_C0000
CLEAR_MSR MTRR_FIX_4K_C8000
CLEAR_MSR MTRR_FIX_4K_D0000
CLEAR_MSR MTRR_FIX_4K_D8000
CLEAR_MSR MTRR_FIX_4K_E0000
CLEAR_MSR MTRR_FIX_4K_F0000
CLEAR_MSR MTRR_FIX_4K_F8000
/*
* Clear variable MTRRs
* Chapter 2.2.5.1
* Intel TXT Software Development Guide (Document: 315168-015)
*/
movl $(MTRR_CAP_MSR), %ecx
rdmsr
andl $(0xff), %eax
movl %eax, %ebx
xorl %eax, %eax
xorl %edx, %edx
jmp cond_clear_var_mtrrs
body_clear_var_mtrrs:
decl %ebx
movl %ebx, %ecx
shll %ecx
addl $(MTRR_PHYS_BASE(0)), %ecx
wrmsr
incl %ecx /* MTRR_PHYS_MASK */
wrmsr
cond_clear_var_mtrrs:
cmpl $0, %ebx
jnz body_clear_var_mtrrs
/*
* Setup BIOS ACM as WB
* Chapter A.1.1
* Intel TXT Software Development Guide (Document: 315168-015)
*/
movl $(MTRR_PHYS_BASE(0)), %ecx
movl 12(%ebp), %eax /* %eax = acmbase */
orl $(6), %eax /* MTRR_TYPE_WB */
movl $0, %edx
wrmsr
/* Round acmsize to next power of two. Required for MTRR programming. */
movl $1, %ebx
movl 16(%ebp), %ecx /* %ebx = acmsize */
dec %ecx
bsr %ecx, %ecx /* find MSB */
inc %ecx
shl %cl, %ebx
movl $(MTRR_PHYS_MASK(0)), %ecx
xorl %eax, %eax
subl %ebx, %eax /* %eax = 4GIB - log2_ceil(ACM SIZE) */
orl $((1 << 11)), %eax /* MTRR_PHYS_MASK_VALID */
movl MTRR_HIGH_MASK, %edx
wrmsr
/* Enable cache - GPF# if not done */
movl %cr0, %eax
andl $(~(CR0_CD | CR0_NW)), %eax
movl %eax, %cr0
/* Enable Numeric error - GPE# if not done */
movl %cr0, %eax
orl $(CR0_NE), %eax
movl %eax, %cr0
/* Enable SMX and FXSTORE - for getsec */
movl %cr4, %eax
orl $(CR4_SMXE | CR4_OSFXSR), %eax
movl %eax, %cr4
/*
* Save GDT
* Chapter A.1.2
* Intel TXT Software Development Guide (Document: 315168-015)
*/
sgdt -48(%ebp)
/* Backup stack pointer */
movd %esp, %xmm0
movd %ebp, %xmm1
/*
* Get function arguments.
* It's important to pass the exact ACM size as it's used by getsec to verify
* the integrity of ACM. Unlike the size for MTRR programming, which needs to
* be power of two.
*
* The following assembly code is based on tboot's tboot/include/txt/smx.h.
*/
movl 8(%ebp), %esi /* flags */
movl 12(%ebp), %ebx /* acm_base */
movl 16(%ebp), %ecx /* acm_size */
movl $0, %edx /* reserved, must be zero */
movl $0, %edi /* must be zero */
movl $2, %eax /* GetSec[ENTERACCS] */
getsec
/* Restore stack pointer */
movd %xmm0, %esp
movd %xmm1, %ebp
/* Reload GDT */
lgdt -48(%ebp)
/* Set cs */
ljmp $0x10, $1f
1:
/* Fix segment registers */
movl $0x18, %eax
movl %eax, %ds
movl %eax, %es
movl %eax, %ss
movl %eax, %fs
movl %eax, %gs
/* Disable cache */
movl %cr0, %eax
orl $(CR0_CD | CR0_NW), %eax
movl %eax, %cr0
/* Pop variable MTRRs in descending order */
movl $(MTRR_CAP_MSR), %ecx
rdmsr
andl $(0xff), %eax
movl %eax, %ebx
jmp cond_pop_var_mtrrs
body_pop_var_mtrrs:
decl %ebx
movl %ebx, %ecx
shll %ecx
addl $(MTRR_PHYS_MASK(0)), %ecx
pop %edx
pop %eax
wrmsr
decl %ecx /* MTRR_PHYS_BASE */
pop %edx
pop %eax
wrmsr
cond_pop_var_mtrrs:
cmpl $0, %ebx
jne body_pop_var_mtrrs
POP_MSR MTRR_FIX_4K_F8000
POP_MSR MTRR_FIX_4K_F0000
POP_MSR MTRR_FIX_4K_E0000
POP_MSR MTRR_FIX_4K_D8000
POP_MSR MTRR_FIX_4K_D0000
POP_MSR MTRR_FIX_4K_C8000
POP_MSR MTRR_FIX_4K_C0000
POP_MSR MTRR_FIX_16K_A0000
POP_MSR MTRR_FIX_16K_80000
POP_MSR MTRR_FIX_64K_00000
POP_MSR IA32_MISC_ENABLE
/* Enable fixed MTRRs */
movl $(MTRR_DEF_TYPE_MSR), %ecx
rdmsr
orl $(MTRR_DEF_TYPE_FIX_EN), %eax
wrmsr
/* Enable cache */
movl %cr0, %eax
andl $(~(CR0_CD | CR0_NW)), %eax
movl %eax, %cr0
/* Pop GDT */
addl $8, %esp
popl %eax
movl %eax, %cr4
popl %eax
movl %eax, %cr0
popal
movl %ebp, %esp
popl %ebp
ret

View file

@ -0,0 +1,241 @@
/* SPDX-License-Identifier: GPL-2.0-only */
#include <console/console.h>
#if CONFIG(SOC_INTEL_COMMON_BLOCK_SA)
#include <intelblocks/systemagent.h>
#endif
#include <arch/mmio.h>
#include <string.h>
#include "txt.h"
#include "txt_register.h"
/**
* Logs microcode or SINIT ACM errors.
* Does not log SBIOS ACM errors.
*/
static void log_txt_error(const char *phase)
{
const uint64_t txt_error = read64((void *)TXT_ERROR);
if (txt_error & ACMERROR_TXT_VALID) {
printk(BIOS_ERR, "%s: Error occurred\n", phase);
if (txt_error & ACMERROR_TXT_EXTERNAL)
printk(BIOS_ERR, " Caused by: External\n");
else
printk(BIOS_ERR, " Caused by: Processor\n");
printk(BIOS_ERR, " Type: ");
switch (txt_error & TXT_ERROR_MASK) {
case 0:
printk(BIOS_ERR, "Legacy Shutdown\n");
break;
case 5:
printk(BIOS_ERR, "Load memory type error in ACM area\n");
break;
case 6:
printk(BIOS_ERR, "Unrecognized ACM format\n");
break;
case 7:
printk(BIOS_ERR, "Failure to authenticate\n");
break;
case 8:
printk(BIOS_ERR, "Invalid ACM format\n");
break;
case 9:
printk(BIOS_ERR, "Unexpected Snoop hit\n");
break;
case 10:
printk(BIOS_ERR, "Invalid event\n");
break;
case 11:
printk(BIOS_ERR, "Invalid MLE\n");
break;
case 12:
printk(BIOS_ERR, "Machine check event\n");
break;
case 13:
printk(BIOS_ERR, "VMXAbort\n");
break;
case 14:
printk(BIOS_ERR, "AC memory corruption\n");
break;
case 15:
printk(BIOS_ERR, "Illegal voltage/bus ratio\n");
break;
default:
printk(BIOS_ERR, "unknown\n");
break;
}
}
}
/**
* Dump useful informaation about the BIOS ACM state.
* Should run right after console_init() in romstage.
* Resets the platform if TXT reset is active and MLE cannot be established.
**/
void intel_txt_log_bios_acm_error(void)
{
uint32_t bios_acm_error;
uint64_t acm_status;
uint64_t txt_error;
printk(BIOS_INFO, "TEE-TXT: State of ACM and ucode update:\n");
bios_acm_error = read32((void *)TXT_BIOSACM_ERRORCODE);
acm_status = read64((void *)TXT_SPAD);
txt_error = read64((void *)TXT_ERROR);
/* Errors by BIOS ACM or FIT */
if ((txt_error & ACMERROR_TXT_VALID) &&
(acm_status & ACMERROR_TXT_VALID)) {
intel_txt_log_acm_error(read32((void *)TXT_BIOSACM_ERRORCODE));
log_txt_error("FIT MICROCODE");
}
/* Errors by SINIT */
if ((txt_error & ACMERROR_TXT_VALID) &&
!(acm_status & ACMERROR_TXT_VALID)) {
intel_txt_log_acm_error(txt_error);
log_txt_error("SINIT");
}
/* Check for fatal ACM error and TXT reset */
uint8_t error = read8((void *)TXT_ESTS);
if (error & TXT_ESTS_TXT_RESET_STS) {
printk(BIOS_CRIT, "TXT-STS: Intel TXT reset detected\n");
intel_txt_log_acm_error(read32((void *)TXT_ERROR));
}
}
/**
* Dump information about the provided ACM.
*/
void txt_dump_acm_info(const struct acm_header_v0 *acm_header)
{
const struct acm_info_table *info = NULL;
if (!acm_header)
return;
printk(BIOS_INFO, "ACM @ %p\n", acm_header);
const size_t acm_size = (acm_header->size & 0xffffff) << 2;
const size_t info_off = (acm_header->header_len + acm_header->scratch_size) * 4;
if (acm_size > (info_off + sizeof(struct acm_info_table)))
info = (const struct acm_info_table *)
((const unsigned char *)acm_header + info_off);
printk(BIOS_INFO, " ACM: Binary Info\n");
if (acm_header->module_type == CHIPSET_ACM)
printk(BIOS_INFO, " Type: Chipset ACM\n");
if (acm_header->module_sub_type == 0)
printk(BIOS_INFO, " Subtype: undefined\n");
else if (acm_header->module_sub_type == 1)
printk(BIOS_INFO, " Subtype: Run at reset\n");
printk(BIOS_INFO, " Header: v%u.%u\n", acm_header->header_version[0],
acm_header->header_version[1]);
printk(BIOS_INFO, " Chipset: %u\n", acm_header->chipset_id);
printk(BIOS_INFO, " Size: %zu\n", acm_size);
switch (acm_header->flags) {
case ACM_FORMAT_FLAGS_PW:
printk(BIOS_INFO, " Flags: PW signed (Production Worthy)\n");
break;
case ACM_FORMAT_FLAGS_NPW:
printk(BIOS_INFO, " Flags: NPW signed (Non Production Worthy)\n");
break;
case ACM_FORMAT_FLAGS_DEBUG:
printk(BIOS_INFO, " Flags: Debug signed\n");
break;
}
if (acm_header->module_vendor == INTEL_ACM_VENDOR)
printk(BIOS_INFO, " Vendor: Intel Corporation\n");
printk(BIOS_INFO, " Date: %x\n", acm_header->date);
switch (acm_header->size) {
case ACM_FORMAT_SIZE_64KB:
printk(BIOS_INFO, " Size: 64KB\n");
printk(BIOS_INFO, " CBnT: no\n");
break;
case ACM_FORMAT_SIZE_128KB:
printk(BIOS_INFO, " Size: 128KB\n");
printk(BIOS_INFO, " CBnT: no\n");
break;
case ACM_FORMAT_SIZE_256KB:
printk(BIOS_INFO, " Size: 256KB\n");
printk(BIOS_INFO, " CBnT: yes\n");
break;
default:
printk(BIOS_INFO, " Size: 0x%08x\n", acm_header->size);
break;
}
printk(BIOS_INFO, " TXT SVN: %u\n", acm_header->txt_svn);
printk(BIOS_INFO, " SE SVN: %u\n", acm_header->se_svn);
if (!info)
return;
printk(BIOS_INFO, " Table info:\n");
printk(BIOS_INFO, " UUID: ");
for (size_t i = 0; i < sizeof(info->uuid); i++)
printk(BIOS_INFO, "%02X ", info->uuid[i]);
printk(BIOS_INFO, "\n");
printk(BIOS_INFO, " Chipset acm type: 0x%x\n", info->chipset_acm_type);
printk(BIOS_INFO, " Capabilities: 0x%x\n", info->capabilities);
}
/**
* Dump information about the chipset's TXT capabilities.
*/
void txt_dump_chipset_info(void)
{
printk(BIOS_INFO, "TEE-TXT: Chipset Key Hash 0x");
for (int i = 0; i < TXT_ACM_KEY_HASH_LEN; i++) {
printk(BIOS_INFO, "%llx", read64((void *)TXT_ACM_KEY_HASH +
(i * sizeof(uint64_t))));
}
printk(BIOS_INFO, "\n");
printk(BIOS_INFO, "TEE-TXT: DIDVID 0x%x\n", read32((void *)TXT_DIDVID));
printk(BIOS_INFO, "TEE-TXT: production fused chipset: %s\n",
(read64((void *)TXT_VER_FSBIF) & TXT_VER_PRODUCTION_FUSED) ? "true" : "false");
}
void txt_dump_regions(void)
{
struct txt_biosdataregion *bdr = NULL;
uintptr_t tseg = 0;
uint64_t reg64;
reg64 = read64((void *)TXT_HEAP_BASE);
if ((reg64 != 0 && reg64 != ~0UL) &&
(read64((void *)(uintptr_t)reg64) >= (sizeof(*bdr) + sizeof(uint64_t))))
bdr = (void *)((uintptr_t)reg64 + sizeof(uint64_t));
printk(BIOS_DEBUG, "TEE-TXT: TSEG 0x%lx\n", tseg * MiB);
printk(BIOS_DEBUG, "TEE-TXT: TXT.HEAP.BASE 0x%llx\n", read64((void *)TXT_HEAP_BASE));
printk(BIOS_DEBUG, "TEE-TXT: TXT.HEAP.SIZE 0x%llx\n", read64((void *)TXT_HEAP_SIZE));
printk(BIOS_DEBUG, "TEE-TXT: TXT.SINIT.BASE 0x%llx\n", read64((void *)TXT_SINIT_BASE));
printk(BIOS_DEBUG, "TEE-TXT: TXT.SINIT.SIZE 0x%llx\n", read64((void *)TXT_SINIT_SIZE));
printk(BIOS_DEBUG, "TEE-TXT: TXT.MSEG.BASE 0x%llx\n", read64((void *)TXT_MSEG_BASE));
printk(BIOS_DEBUG, "TEE-TXT: TXT.MSEG.SIZE 0x%llx\n", read64((void *)TXT_MSEG_SIZE));
if (bdr) {
printk(BIOS_DEBUG, "TEE-TXT: BiosDataRegion.bios_sinit_size 0x%x\n",
bdr->bios_sinit_size);
printk(BIOS_DEBUG, "TEE-TXT: BiosDataRegion.lcp_pd_size 0x%llx\n",
bdr->lcp_pd_size);
printk(BIOS_DEBUG, "TEE-TXT: BiosDataRegion.lcp_pd_base 0x%llx\n",
bdr->lcp_pd_base);
}
}

View file

@ -0,0 +1,382 @@
/* SPDX-License-Identifier: GPL-2.0-only */
#include <arch/mmio.h>
#include <arch/acpi.h>
#include <bootstate.h>
#include <bootmem.h>
#include <console/console.h>
#include <stdint.h>
#include <cbfs.h>
#include <cpu/intel/common/common.h>
#include <cpu/x86/msr.h>
#include <lib.h>
#include <device/pci_ops.h>
#if CONFIG(SOC_INTEL_FSP_BROADWELL_DE)
#include <soc/broadwell_de.h>
#include <soc/ramstage.h>
#endif
#include "txt.h"
#include "txt_register.h"
#include "txt_getsec.h"
/* FIXME: Seems to work only on some platforms */
static void log_ibb_measurements(void)
{
const uint64_t mseg_size = read64((void *)TXT_MSEG_SIZE);
uint64_t mseg_base = read64((void *)TXT_MSEG_BASE);
if (!mseg_size || !mseg_base || mseg_size <= mseg_base)
return;
/*
* MSEG SIZE and MSEG BASE might contain random values.
* Assume below 4GiB and 8byte aligned.
*/
if (mseg_base & ~0xfffffff8ULL || mseg_size & ~0xfffffff8ULL)
return;
printk(BIOS_INFO, "TEE-TXT: IBB Hash 0x");
for (; mseg_base < mseg_size; mseg_base++)
printk(BIOS_INFO, "%02X", read8((void *)(uintptr_t)mseg_base));
printk(BIOS_INFO, "\n");
}
void bootmem_platform_add_ranges(void)
{
uint64_t status = read64((void *)TXT_SPAD);
if (status & ACMSTS_TXT_DISABLED)
return;
/* Chapter 5.5.5 Intel TXT reserved memory */
bootmem_add_range(TXT_RESERVED_SPACE,
TXT_RESERVED_SPACE_SIZE,
BM_MEM_RESERVED);
/* Intel TPM decode memory */
bootmem_add_range(TXT_TPM_DECODE_AREA,
TXT_RESERVED_SPACE - TXT_TPM_DECODE_AREA,
BM_MEM_RESERVED);
/* Intel TXT public space memory */
bootmem_add_range(TXT_PUBLIC_SPACE,
TXT_TPM_DECODE_AREA - TXT_PUBLIC_SPACE,
BM_MEM_RESERVED);
/* Intel TXT private space memory */
bootmem_add_range(TXT_PRIVATE_SPACE,
TXT_PUBLIC_SPACE - TXT_PRIVATE_SPACE,
BM_MEM_RESERVED);
const uint32_t txt_dev_memory = read32((void *)TXT_DPR) &
(TXT_DPR_TOP_ADDR_MASK << TXT_DPR_TOP_ADDR_SHIFT);
const uint32_t txt_dev_size =
(read32((void *)TXT_DPR) >> TXT_DPR_LOCK_SIZE_SHIFT) &
TXT_DPR_LOCK_SIZE_MASK;
/* Chapter 5.5.6 Intel TXT Device Memory */
bootmem_add_range(txt_dev_memory - txt_dev_size * MiB,
txt_dev_size * MiB,
BM_MEM_RESERVED);
}
static bool get_wake_error_status(void)
{
const uint8_t error = read8((void *)TXT_ESTS);
return !!(error & TXT_ESTS_WAKE_ERROR_STS);
}
static void check_secrets_txt(void *unused)
{
uint64_t status = read64((void *)TXT_SPAD);
if (status & ACMSTS_TXT_DISABLED)
return;
/* Check for fatal ACM error and TXT reset */
if (get_wake_error_status()) {
/*
* Check if secrets bit needs to be reset. Only platforms that support
* CONFIG(PLATFORM_HAS_DRAM_CLEAR) will be able to run this code.
* Assume all memory really was cleared.
*
* TXT will issue a platform reset to come up sober.
*/
if (intel_txt_memory_has_secrets()) {
printk(BIOS_INFO, "TEE-TXT: Wiping TEE...\n");
intel_txt_run_bios_acm(ACMINPUT_CLEAR_SECRETS);
/* Should never reach this point ... */
intel_txt_log_acm_error(read32((void *)TXT_BIOSACM_ERRORCODE));
die("Waiting for platform reset...\n");
}
}
}
BOOT_STATE_INIT_ENTRY(BS_POST_DEVICE, BS_ON_ENTRY, check_secrets_txt, NULL);
/**
* Log TXT startup errors, check all bits for TXT, run BIOSACM using
* GETSEC[ENTERACCS].
*
* If a "TXT reset" is detected or "memory had secrets" is set, then do nothing as
* 1. Running ACMs will cause a TXT-RESET
* 2. Memory will be scrubbed in BS_DEV_INIT
* 3. TXT-RESET will be issued by code above later
*
*/
static void init_intel_txt(void *unused)
{
const uint64_t status = read64((void *)TXT_SPAD);
if (status & ACMSTS_TXT_DISABLED)
return;
printk(BIOS_INFO, "TEE-TXT: Initializing TEE...\n");
intel_txt_log_spad();
if (CONFIG(INTEL_TXT_LOGGING)) {
intel_txt_log_bios_acm_error();
txt_dump_chipset_info();
}
printk(BIOS_INFO, "TEE-TXT: Validate TEE...\n");
if (intel_txt_prepare_txt_env()) {
printk(BIOS_ERR, "TEE-TXT: Failed to prepare TXT environment\n");
return;
}
/* Check for fatal ACM error and TXT reset */
if (get_wake_error_status()) {
/* Can't run ACMs with TXT_ESTS_WAKE_ERROR_STS set */
printk(BIOS_ERR, "TEE-TXT: Fatal BIOS ACM error reported\n");
return;
}
printk(BIOS_INFO, "TEE-TXT: Testing BIOS ACM calling code...\n");
/*
* Test BIOS ACM code.
* ACM should do nothing on reserved functions, and return an error code
* in TXT_BIOSACM_ERRORCODE. Tests showed that this is not true.
* Use special function "NOP" that does 'nothing'.
*/
if (intel_txt_run_bios_acm(ACMINPUT_NOP) < 0) {
printk(BIOS_ERR, "TEE-TXT: Error calling BIOS ACM with NOP function.\n");
return;
}
if (status & (ACMSTS_BIOS_TRUSTED | ACMSTS_IBB_MEASURED)) {
log_ibb_measurements();
int s3resume = acpi_is_wakeup_s3();
if (!s3resume) {
printk(BIOS_INFO, "TEE-TXT: Scheck...\n");
if (intel_txt_run_bios_acm(ACMINPUT_SCHECK) < 0) {
printk(BIOS_ERR, "TEE-TXT: Error calling BIOS ACM.\n");
return;
}
}
}
}
BOOT_STATE_INIT_ENTRY(BS_DEV_INIT, BS_ON_EXIT, init_intel_txt, NULL);
static void push_sinit_heap(u8 **heap_ptr, void *data, size_t data_length)
{
/* Push size */
const uint64_t tmp = data_length + 8;
memcpy(*heap_ptr, &tmp, 8);
*heap_ptr += 8;
if (data_length) {
/* Push data */
memcpy(*heap_ptr, data, data_length);
*heap_ptr += data_length;
}
}
/**
* Finalize the TXT device.
*
* - Lock TXT register.
* - Protect TSEG using DMA protected regions.
* - Setup TXT regions.
* - Place SINIT ACM in TXT_SINIT memory segment.
* - Fill TXT BIOSDATA region.
*/
static void lockdown_intel_txt(void *unused)
{
const uint64_t status = read64((void *)TXT_SPAD);
uintptr_t tseg = 0;
if (status & ACMSTS_TXT_DISABLED)
return;
printk(BIOS_INFO, "TEE-TXT: Locking TEE...\n");
/* Lock TXT config, unlocks TXT_HEAP_BASE */
if (intel_txt_run_bios_acm(ACMINPUT_LOCK_CONFIG) < 0) {
printk(BIOS_ERR, "TEE-TXT: Failed to lock registers.\n");
printk(BIOS_ERR, "TEE-TXT: SINIT won't be supported.\n");
return;
}
if (CONFIG(SOC_INTEL_FSP_BROADWELL_DE))
tseg = sa_get_tseg_base() >> 20;
/*
* Document Number: 558294
* Chapter 5.5.6.1 DMA Protection Memory Region
*/
const u8 dpr_capable = !!(read64((void *)TXT_CAPABILITIES) &
TXT_CAPABILITIES_DPR);
printk(BIOS_INFO, "TEE-TXT: DPR capable %x\n", dpr_capable);
if (dpr_capable) {
/* Protect 3 MiB below TSEG and lock register */
write64((void *)TXT_DPR, (TXT_DPR_TOP_ADDR(tseg) |
TXT_DPR_LOCK_SIZE(3) |
TXT_DPR_LOCK_MASK));
#if CONFIG(SOC_INTEL_FSP_BROADWELL_DE)
broadwell_de_set_dpr(tseg, 3 * MiB);
broadwell_de_lock_dpr();
#endif
printk(BIOS_INFO, "TEE-TXT: TXT.DPR 0x%08x\n",
read32((void *)TXT_DPR));
}
/*
* Document Number: 558294
* Chapter 5.5.6.3 Intel TXT Heap Memory Region
*/
write64((void *)TXT_HEAP_SIZE, 0xE0000);
write64((void *)TXT_HEAP_BASE,
ALIGN_DOWN((tseg * MiB) - read64((void *)TXT_HEAP_SIZE), 4096));
/*
* Document Number: 558294
* Chapter 5.5.6.2 SINIT Memory Region
*/
write64((void *)TXT_SINIT_SIZE, 0x20000);
write64((void *)TXT_SINIT_BASE,
ALIGN_DOWN(read64((void *)TXT_HEAP_BASE) -
read64((void *)TXT_SINIT_SIZE), 4096));
/*
* BIOS Data Format
* Chapter C.2
* Intel TXT Software Development Guide (Document: 315168-015)
*/
struct {
struct txt_biosdataregion bdr;
struct txt_heap_acm_element heap_acm;
struct txt_extended_data_element_header end;
} __packed data = {0};
/* TPM2.0 requires version 6 of BDT */
if (CONFIG(TPM2))
data.bdr.version = 6;
else
data.bdr.version = 5;
data.bdr.no_logical_procs = dev_count_cpu();
void *sinit_base = (void *)(uintptr_t)read64((void *)TXT_SINIT_BASE);
data.bdr.bios_sinit_size = cbfs_boot_load_file(CONFIG_INTEL_TXT_CBFS_SINIT_ACM,
sinit_base,
read64((void *)TXT_SINIT_SIZE),
CBFS_TYPE_RAW);
if (data.bdr.bios_sinit_size) {
printk(BIOS_INFO, "TEE-TXT: Placing SINIT ACM in memory.\n");
if (CONFIG(INTEL_TXT_LOGGING))
txt_dump_acm_info(sinit_base);
} else {
printk(BIOS_ERR, "TEE-TXT: Couldn't locate SINIT ACM in CBFS.\n");
/* Clear memory */
memset(sinit_base, 0, read64((void *)TXT_SINIT_SIZE));
}
struct cbfsf file;
/* The following have been removed from BIOS Data Table in version 6 */
if (!cbfs_boot_locate(&file, CONFIG_INTEL_TXT_CBFS_BIOS_POLICY, NULL)) {
struct region_device policy;
cbfs_file_data(&policy, &file);
void *policy_data = rdev_mmap_full(&policy);
size_t policy_len = region_device_sz(&policy);
if (policy_data && policy_len) {
/* Point to FIT Type 9 entry in flash */
data.bdr.lcp_pd_base = (uintptr_t)policy_data;
data.bdr.lcp_pd_size = (uint64_t)policy_len;
rdev_munmap(&policy, policy_data);
} else {
printk(BIOS_ERR, "TEE-TXT: Couldn't map LCP PD Policy from CBFS.\n");
}
} else {
printk(BIOS_ERR, "TEE-TXT: Couldn't locate LCP PD Policy in CBFS.\n");
}
data.bdr.support_acpi_ppi = 0;
data.bdr.platform_type = 0;
/* Extended elements - ACM addresses */
data.heap_acm.header.type = HEAP_EXTDATA_TYPE_ACM;
data.heap_acm.header.size = sizeof(data.heap_acm);
if (data.bdr.bios_sinit_size) {
data.heap_acm.num_acms = 2;
data.heap_acm.acm_addrs[1] = (uintptr_t)sinit_base;
} else {
data.heap_acm.num_acms = 1;
}
data.heap_acm.acm_addrs[0] =
(uintptr_t)cbfs_boot_map_with_leak(CONFIG_INTEL_TXT_CBFS_BIOS_ACM,
CBFS_TYPE_RAW,
NULL);
/* Extended elements - End marker */
data.end.type = HEAP_EXTDATA_TYPE_END;
data.end.size = sizeof(data.end);
/* Fill TXT.HEAP.BASE with 4 subregions */
u8 *heap_struct = (void *)((uintptr_t)read64((void *)TXT_HEAP_BASE));
/* BiosData */
push_sinit_heap(&heap_struct, &data, sizeof(data));
/* OsMLEData */
/* FIXME: Does firmware need to write this? */
push_sinit_heap(&heap_struct, NULL, 0);
/* OsSinitData */
/* FIXME: Does firmware need to write this? */
push_sinit_heap(&heap_struct, NULL, 0);
/* SinitMLEData */
/* FIXME: Does firmware need to write this? */
push_sinit_heap(&heap_struct, NULL, 0);
/*
* FIXME: Server-TXT capable platforms need to install an STM in SMM and set up MSEG.
*/
/**
* Chapter 5.10.1 SMM in the Intel TXT for Servers Environment
* Disable MSEG.
*/
write64((void *)TXT_MSEG_SIZE, 0);
write64((void *)TXT_MSEG_BASE, 0);
if (CONFIG(INTEL_TXT_LOGGING))
txt_dump_regions();
}
BOOT_STATE_INIT_ENTRY(BS_POST_DEVICE, BS_ON_EXIT, lockdown_intel_txt, NULL);

View file

@ -0,0 +1,27 @@
/* SPDX-License-Identifier: GPL-2.0-only */
#ifndef SECURITY_INTEL_TXT_H_
#define SECURITY_INTEL_TXT_H_
#include <types.h>
/* Error codes */
#define ACM_E_TYPE_NOT_MATCH 0x01
#define ACM_E_MODULE_SUB_TYPE_WRONG 0x02
#define ACM_E_MODULE_VENDOR_NOT_INTEL 0x03
#define ACM_E_SIZE_INCORRECT 0x04
#define ACM_E_CANT_CALL_GETSEC 0x05
#define ACM_E_NOT_FIT_INTO_CPU_ACM_MEM 0x06
#define ACM_E_NO_INFO_TABLE 0x07
#define ACM_E_NOT_BIOS_ACM 0x08
#define ACM_E_UUID_NOT_MATCH 0x09
#define ACM_E_PLATFORM_IS_NOT_PROD 0x10
void intel_txt_log_bios_acm_error(void);
int intel_txt_log_acm_error(const uint32_t acm_error);
void intel_txt_log_spad(void);
bool intel_txt_memory_has_secrets(void);
int intel_txt_run_bios_acm(const u8 input_params);
bool intel_txt_prepare_txt_env(void);
#endif /* SECURITY_INTEL_TXT_H_ */

View file

@ -0,0 +1,21 @@
/* SPDX-License-Identifier: GPL-2.0-only */
#ifndef SECURITY_INTEL_TXT_GETSEC_H_
#define SECURITY_INTEL_TXT_GETSEC_H_
#include <stdint.h>
bool getsec_parameter(uint32_t *version_mask,
uint32_t *version_numbers_supported,
uint32_t *max_size_acm_area,
uint32_t *memory_type_mask,
uint32_t *senter_function_disable,
uint32_t *txt_feature_flags);
bool getsec_capabilities(uint32_t *eax);
void getsec_enteraccs(const uint32_t esi,
const uint32_t acm_base,
const uint32_t acm_size);
#endif /* SECURITY_INTEL_TXT_REGISTER_H_ */

View file

@ -0,0 +1,267 @@
/* SPDX-License-Identifier: GPL-2.0-only */
#ifndef SECURITY_INTEL_TXT_REGISTER_H_
#define SECURITY_INTEL_TXT_REGISTER_H_
#include <types.h>
#include <stddef.h>
/*
* Document: 315168-016
* Intel Trusted Execution Technology (Intel TXT)
* Software Development Guide
* Chapter B
*/
#define TXT_BASE 0xfed30000UL
#define TXT_STS (TXT_BASE + 0)
#define TXT_ESTS (TXT_BASE + 8)
#define TXT_ESTS_TXT_RESET_STS (1 << 0)
/*
* Chapter 6
* Intel Trusted Execution Technology Lab Handout
*/
#define TXT_ESTS_WAKE_ERROR_STS (1 << 6)
#define TXT_ERROR (TXT_BASE + 0x30)
#define ACMERROR_TXT_VALID (1ul << 31)
#define ACMERROR_TXT_EXTERNAL (1ul << 30)
#define ACMERROR_TXT_PROGRESS_SHIFT 16
#define ACMERROR_TXT_MINOR_SHIFT 15
#define ACMERROR_TXT_MAJOR_SHIFT 10
#define ACMERROR_TXT_CLASS_SHIFT 4
#define ACMERROR_TXT_TYPE_SHIFT 0
#define ACMERROR_TXT_PROGRESS_CODE (0xffull << ACMERROR_TXT_PROGRESS_SHIFT)
#define ACMERROR_TXT_MINOR_CODE (0x01ull << ACMERROR_TXT_MINOR_SHIFT)
#define ACMERROR_TXT_MAJOR_CODE (0x1full << ACMERROR_TXT_MAJOR_SHIFT)
#define ACMERROR_TXT_CLASS_CODE (0x3full << ACMERROR_TXT_CLASS_SHIFT)
#define ACMERROR_TXT_TYPE_CODE (0x0full << ACMERROR_TXT_TYPE_SHIFT)
#define ACMERROR_TXT_AC_MODULE_TYPE_BIOS 0
#define ACMERROR_TXT_AC_MODULE_TYPE_SINIT 1
#define TXT_ERROR_MASK (0x3ff << 0)
#define TXT_CMD_RESET (TXT_BASE + 0x38)
#define TXT_CMD_CLOSE_PRIVATE (TXT_BASE + 0x48)
/* Present in Document Number: 315168-016. */
#define TXT_SPAD (TXT_BASE + 0xa0)
#define ACMSTS_IBB_MEASURED (1ull << 63)
#define ACMSTS_VERIFICATION_ERROR (1ull << 62)
#define ACMSTS_BG_STARTUP_ERROR (1ull << 61) /* CBnT platforms only */
#define ACMSTS_TXT_DISABLED (1ull << 60) /* disabled by FIT type 0xA record */
#define ACMSTS_BIOS_TRUSTED (1ull << 59)
#define ACMSTS_MEM_CLEAR_POWER_DOWN (1ull << 47)
#define ACMSTS_TXT_STARTUP_SUCCESS (1ull << 30)
#define TXT_VER_FSBIF (TXT_BASE + 0x100)
#define TXT_VER_PRODUCTION_FUSED (1ull << 31)
#define TXT_DIDVID (TXT_BASE + 0x110)
/*
* Chapter 6
* Intel Trusted Execution Technology Lab Handout
*/
#define TXT_CAPABILITIES (TXT_BASE + 0x200)
#define TXT_CAPABILITIES_DPR (1ull << 26)
#define TXT_CAPABILITIES_PMRC (1ull << 19)
#define TXT_VER_QPIIF (TXT_BASE + 0x200)
#define TXT_SINIT_BASE (TXT_BASE + 0x270)
#define TXT_SINIT_SIZE (TXT_BASE + 0x278)
#define TXT_MLE_JOIN (TXT_BASE + 0x290)
#define TXT_HEAP_BASE (TXT_BASE + 0x300)
#define TXT_HEAP_SIZE (TXT_BASE + 0x308)
/*
* Chapter 6
* Intel Trusted Execution Technology Lab Handout
*/
#define TXT_MSEG_BASE (TXT_BASE + 0x310)
#define TXT_MSEG_SIZE (TXT_BASE + 0x318)
/*
* Chapter 5.4.2.1
* Intel Trusted Execution Technology Lab Handout
*/
#define TXT_BIOSACM_ERRORCODE (TXT_BASE + 0x328)
#define TXT_DPR (TXT_BASE + 0x330)
#define TXT_DPR_LOCK_SHIFT 0
#define TXT_DPR_LOCK_SIZE_SHIFT 4
#define TXT_DPR_LOCK_SIZE_MASK 0xff
#define TXT_DPR_TOP_ADDR_SHIFT 20
#define TXT_DPR_TOP_ADDR_MASK 0xfff
#define TXT_DPR_LOCK_MASK (1 << TXT_DPR_LOCK_SHIFT)
#define TXT_DPR_LOCK_SIZE(x) ((x) << TXT_DPR_LOCK_SIZE_SHIFT)
#define TXT_DPR_TOP_ADDR(x) ((x) << TXT_DPR_TOP_ADDR_SHIFT)
#define TXT_ACM_KEY_HASH (TXT_BASE + 0x400)
#define TXT_ACM_KEY_HASH_LEN 0x4
#define TXT_E2STS (TXT_BASE + 0x8f0)
#define TXT_E2STS_SECRET_STS (1ull << 1)
/*
* TXT Memory regions
* Chapter 5.3
* Intel Trusted Execution Technology Lab Handout
*/
#define TXT_PRIVATE_SPACE 0xfed20000UL
#define TXT_PUBLIC_SPACE 0xfed30000UL
#define TXT_TPM_DECODE_AREA 0xfed40000UL
#define TXT_RESERVED_SPACE 0xfed50000UL
#define TXT_RESERVED_SPACE_SIZE 0x3ffff
/* ESI flags for GETSEC[ENTERACCS] see Reference Number: 323372-017 */
#define ACMINPUT_RESET_TPM_AUXILIARY_INDICIES 2
#define ACMINPUT_NOP 3
#define ACMINPUT_SCHECK 4
#define ACMINPUT_CLEAR_SECRETS 5
#define ACMINPUT_LOCK_CONFIG 6
/*
* GetSec EAX value.
* SAFER MODE EXTENSIONS REFERENCE.
* Intel 64 and IA-32 Architectures Software Developer Manuals Vol 2
* Order Number: 325383-060US
*/
#define IA32_GETSEC_CAPABILITIES 0
#define IA32_GETSEC_ENTERACCS 2
#define IA32_GETSEC_SENTER 4
#define IA32_GETSEC_SEXIT 5
#define IA32_GETSEC_PARAMETERS 6
#define IA32_GETSEC_SMCTRL 7
#define IA32_GETSEC_WAKEUP 8
#define GETSEC_PARAMS_TXT_EXT (1ul << 5)
#define GETSEC_PARAMS_TXT_EXT_CRTM_SUPPORT (1ul << 1)
#define GETSEC_PARAMS_TXT_EXT_MACHINE_CHECK (1ul << 6)
/* ACM defines */
#define INTEL_ACM_VENDOR 0x00008086
#define ACM_FORMAT_FLAGS_PW 0x00000000
#define ACM_FORMAT_FLAGS_NPW (1 << 14)
#define ACM_FORMAT_FLAGS_DEBUG (1 << 15)
/* Old ACMs are power of two aligned, newer ACMs are not */
#define ACM_FORMAT_SIZE_64KB (64 * KiB / 4)
#define ACM_FORMAT_SIZE_128KB (128 * KiB / 4)
#define ACM_FORMAT_SIZE_256KB (256 * KiB / 4)
/* MSRs */
#define IA32_MCG_STATUS 0x17a
typedef enum {
CHIPSET_ACM = 2,
} acm_module_type;
typedef enum {
BIOS = 0,
SINIT = 1,
} acm_module_sub_type;
/*
* ACM Header v0.0 without dynamic part
* Chapter A.1
* Intel TXT Software Development Guide (Document: 315168-015)
*/
struct __packed acm_header_v0 {
uint16_t module_type;
uint16_t module_sub_type;
uint32_t header_len;
uint16_t header_version[2];
uint16_t chipset_id;
uint16_t flags;
uint32_t module_vendor;
uint32_t date;
uint32_t size;
uint16_t txt_svn;
uint16_t se_svn;
uint32_t code_control;
uint32_t error_entry_point;
uint32_t gdt_limit;
uint32_t gdt_ptr;
uint32_t seg_sel;
uint32_t entry_point;
uint8_t reserved2[64];
uint32_t key_size;
uint32_t scratch_size;
uint8_t rsa2048_pubkey[256];
uint32_t pub_exp;
uint8_t rsa2048_sig[256];
uint32_t scratch[143];
uint8_t user_area[];
};
struct __packed acm_info_table {
uint8_t uuid[16];
uint8_t chipset_acm_type;
uint8_t version;
uint16_t length;
uint32_t chipset_id_list;
uint32_t os_sinit_data_ver;
uint32_t min_mle_hdr_ver;
uint32_t capabilities;
uint8_t acm_ver;
uint8_t reserved[3];
};
/*
* Extended Data Elements
* Chapter C.1
* Intel TXT Software Development Guide (Document: 315168-015)
*/
struct __packed txt_extended_data_element_header {
uint32_t type;
uint32_t size;
uint8_t data[0];
};
#define HEAP_EXTDATA_TYPE_END 0
#define HEAP_EXTDATA_TYPE_BIOS_SPEC_VER 1
#define HEAP_EXTDATA_TYPE_ACM 2
#define HEAP_EXTDATA_TYPE_CUSTOM 4
struct __packed txt_heap_acm_element {
struct txt_extended_data_element_header header;
uint32_t num_acms; // must greater 0, smaller than 3
uint64_t acm_addrs[2];
};
/*
* BIOS Data Format
* Chapter C.2
* Intel TXT Software Development Guide (Document: 315168-015)
*/
struct __packed txt_biosdataregion {
uint32_t version;
uint32_t bios_sinit_size;
uint64_t lcp_pd_base;
uint64_t lcp_pd_size;
uint32_t no_logical_procs;
uint32_t sinit_flags;
union {
uint32_t mle_flags;
struct {
uint32_t support_acpi_ppi : 1;
uint32_t platform_type : 2;
};
};
u8 extended_data_elements[0];
};
void txt_dump_regions(void);
void txt_dump_chipset_info(void);
void txt_dump_acm_info(const struct acm_header_v0 *acm_header);
#endif /* SECURITY_INTEL_TXT_REGISTER_H_ */

View file

@ -14,7 +14,8 @@
* GNU General Public License for more details.
*/
#include <types.h>
#include <stdint.h>
#include <security/intel/txt/txt.h>
#include "memory.h"
/**
@ -27,6 +28,9 @@ bool security_clear_dram_request(void)
if (CONFIG(SECURITY_CLEAR_DRAM_ON_REGULAR_BOOT))
return true;
if (CONFIG(INTEL_TXT) && intel_txt_memory_has_secrets())
return true;
/* TODO: Add TEE environments here */
return false;

View file

@ -210,11 +210,28 @@ uint32_t tpm_extend_pcr(int pcr, enum vb2_hash_algorithm digest_algo,
uint8_t *digest, size_t digest_len, const char *name)
{
uint32_t result;
uint16_t algorithm = 0;
if (!digest)
return TPM_E_IOERROR;
result = tlcl_extend(pcr, digest, NULL);
#if CONFIG(TPM2)
switch (digest_algo) {
case VB2_HASH_SHA1:
algorithm = TPM_ALG_SHA1;
break;
case VB2_HASH_SHA256:
algorithm = TPM_ALG_SHA256;
break;
case VB2_HASH_SHA512:
algorithm = TPM_ALG_SHA512;
break;
default:
return TPM_E_HASH_ERROR;
}
#endif
result = tlcl_extend(pcr, algorithm, digest, digest_len, NULL);
if (result != TPM_SUCCESS)
return result;

View file

@ -184,7 +184,8 @@ uint32_t tlcl_lock_nv_write(uint32_t index);
/**
* Perform a TPM_Extend.
*/
uint32_t tlcl_extend(int pcr_num, const uint8_t *in_digest,
uint32_t tlcl_extend(int pcr_num, uint16_t algorithm,
const uint8_t *in_digest, size_t in_digest_len,
uint8_t *out_digest);
/**

View file

@ -341,7 +341,8 @@ uint32_t tlcl_set_global_lock(void)
return tlcl_write(TPM_NV_INDEX0, (uint8_t *) &x, 0);
}
uint32_t tlcl_extend(int pcr_num, const uint8_t *in_digest,
uint32_t tlcl_extend(int pcr_num, uint16_t algorithm,
const uint8_t *in_digest, size_t in_digest_len,
uint8_t *out_digest)
{
struct s_tpm_extend_cmd cmd;
@ -350,8 +351,11 @@ uint32_t tlcl_extend(int pcr_num, const uint8_t *in_digest,
memcpy(&cmd, &tpm_extend_cmd, sizeof(cmd));
to_tpm_uint32(cmd.buffer + tpm_extend_cmd.pcrNum, pcr_num);
memcpy(cmd.buffer + cmd.inDigest, in_digest, kPcrDigestLength);
if (in_digest_len != kPcrDigestLength)
return TPM_E_HASH_ERROR;
memcpy(cmd.buffer + cmd.inDigest, in_digest, kPcrDigestLength);
result = tlcl_send_receive(cmd.buffer, response, sizeof(response));
if (result != TPM_SUCCESS)
return result;

View file

@ -127,21 +127,47 @@ uint32_t tlcl_assert_physical_presence(void)
}
/*
* The caller will provide the digest in a 32 byte buffer, let's consider it a
* sha256 digest.
* The caller will provide the pcr index, digest algorithm and
* a byte buffer to extend into the TPM.
*/
uint32_t tlcl_extend(int pcr_num, const uint8_t *in_digest,
uint32_t tlcl_extend(int pcr_num, uint16_t algorithm,
const uint8_t *in_digest, size_t in_digest_len,
uint8_t *out_digest)
{
struct tpm2_pcr_extend_cmd pcr_ext_cmd;
struct tpm2_response *response;
uint16_t algorithm_size;
pcr_ext_cmd.pcrHandle = HR_PCR + pcr_num;
pcr_ext_cmd.digests.count = 1;
pcr_ext_cmd.digests.digests[0].hashAlg = TPM_ALG_SHA256;
memcpy(pcr_ext_cmd.digests.digests[0].digest.sha256, in_digest,
sizeof(pcr_ext_cmd.digests.digests[0].digest.sha256));
pcr_ext_cmd.digests.digests[0].hashAlg = algorithm;
algorithm_size = tlcl_get_hash_size_from_algo(algorithm);
if (algorithm_size == 0)
return TPM_E_HASH_ERROR;
if (in_digest_len != algorithm_size)
return TPM_E_HASH_ERROR;
switch (algorithm) {
case TPM_ALG_SHA1:
memcpy(pcr_ext_cmd.digests.digests[0].digest.sha1, in_digest, in_digest_len);
break;
case TPM_ALG_SHA256:
memcpy(pcr_ext_cmd.digests.digests[0].digest.sha256, in_digest, in_digest_len);
break;
case TPM_ALG_SHA384:
memcpy(pcr_ext_cmd.digests.digests[0].digest.sha384, in_digest, in_digest_len);
break;
case TPM_ALG_SHA512:
memcpy(pcr_ext_cmd.digests.digests[0].digest.sha512, in_digest, in_digest_len);
break;
case TPM_ALG_SM3_256:
memcpy(pcr_ext_cmd.digests.digests[0].digest.sm3_256, in_digest, in_digest_len);
break;
default:
return TPM_E_HASH_ERROR;
}
response = tpm_process_command(TPM2_PCR_Extend, &pcr_ext_cmd);
printk(BIOS_INFO, "%s: response is %x\n",

View file

@ -46,7 +46,7 @@ vb2_error_t vboot_extend_pcr(struct vb2_context *ctx, int pcr,
switch (which_digest) {
/* SHA1 of (devmode|recmode|keyblock) bits */
case BOOT_MODE_PCR:
return tpm_extend_pcr(pcr, VB2_HASH_SHA256, buffer, size,
return tpm_extend_pcr(pcr, VB2_HASH_SHA1, buffer, size,
TPM_PCR_BOOT_MODE);
/* SHA256 of HWID */
case HWID_DIGEST_PCR:

View file

@ -250,4 +250,7 @@ void pch_log_state(void);
void enable_pm_timer_emulation(void);
/* STM Support */
uint16_t get_pmbase(void);
#endif

View file

@ -246,3 +246,9 @@ int vbnv_cmos_failed(void)
return rtc_failure;
}
/* STM Support */
uint16_t get_pmbase(void)
{
return (uint16_t) ACPI_BASE_ADDRESS;
}

View file

@ -155,4 +155,7 @@ void disable_gpe(uint32_t mask);
/* Return the selected ACPI SCI IRQ */
int acpi_sci_irq(void);
/* STM Support */
uint16_t get_pmbase(void);
#endif

View file

@ -458,3 +458,9 @@ int vboot_platform_is_resuming(void)
return acpi_sleep_from_pm1(inl(ACPI_BASE_ADDRESS + PM1_CNT)) == ACPI_S3;
}
/* STM Support */
uint16_t get_pmbase(void)
{
return (uint16_t) ACPI_BASE_ADDRESS;
}

View file

@ -172,5 +172,8 @@ void pmc_set_disb(void);
/* Clear PMCON status bits */
void pmc_clear_pmcon_sts(void);
/* STM Support */
uint16_t get_pmbase(void);
#endif /* !defined(__ACPI__) */
#endif

View file

@ -273,3 +273,9 @@ void soc_fill_power_state(struct chipset_power_state *ps)
printk(BIOS_DEBUG, "GBLRST_CAUSE: %08x %08x\n",
ps->gblrst_cause[0], ps->gblrst_cause[1]);
}
/* STM Support */
uint16_t get_pmbase(void)
{
return (uint16_t) ACPI_BASE_ADDRESS;
}

View file

@ -23,6 +23,7 @@ config CPU_SPECIFIC_OPTIONS
select SUPPORT_CPU_UCODE_IN_CBFS
select INTEL_DESCRIPTOR_MODE_CAPABLE
select HAVE_SMI_HANDLER
select X86_SMM_LOADER_VERSION2
select TSC_MONOTONIC_TIMER
select HAVE_FSP_BIN
select CPU_INTEL_FIRMWARE_INTERFACE_TABLE
@ -94,6 +95,10 @@ config HPET_MIN_TICKS
hex
default 0x80
config ENABLE_VMX
bool "Enable VMX for virtualization"
default y
## Broadwell-DE Specific FSP Kconfig
source src/soc/intel/fsp_broadwell_de/fsp/Kconfig

View file

@ -271,11 +271,11 @@ void acpi_fill_in_fadt(acpi_fadt_t *fadt, acpi_facs_t *facs, void *dsdt)
fadt->x_gpe0_blk.space_id = ACPI_ADDRESS_SPACE_IO;
fadt->x_gpe0_blk.bit_width = 64; /* EventStatus + EventEnable */
fadt->x_gpe0_blk.bit_offset = 0;
fadt->x_gpe0_blk.access_size = ACPI_ACCESS_SIZE_DWORD_ACCESS;
fadt->x_gpe0_blk.access_size = ACPI_ACCESS_SIZE_BYTE_ACCESS;
fadt->x_gpe0_blk.addrl = fadt->gpe0_blk;
fadt->x_gpe0_blk.addrh = 0x00;
fadt->x_gpe1_blk.space_id = ACPI_ADDRESS_SPACE_IO;
fadt->x_gpe1_blk.space_id = 0;
fadt->x_gpe1_blk.bit_width = 0;
fadt->x_gpe1_blk.bit_offset = 0;
fadt->x_gpe1_blk.access_size = 0;

View file

@ -25,6 +25,8 @@
struct soc_intel_fsp_broadwell_de_config {
/* PCIe completion timeout value */
int pcie_compltoval;
/* LPC Generic Memory Range Register value */
uint32_t lpc_lgmr;
};
typedef struct soc_intel_fsp_broadwell_de_config config_t;

View file

@ -37,6 +37,7 @@
#define LPC_GEN2_DEC 0x88
#define LPC_GEN3_DEC 0x8c
#define LPC_GEN4_DEC 0x90
#define LGMR 0x98 /* LPC Generic Memory Range */
#define GEN_PMCON_1 0xA0
#define SMI_LOCK (1 << 4)
#define SMI_LOCK_GP6 (1 << 5)

View file

@ -27,4 +27,8 @@
void save_dimm_info(void);
/* Determine if memory configuration has been locked by TXT */
bool memory_config_is_locked(void);
#endif

View file

@ -39,4 +39,9 @@
#define MSR_PRMRR_PHYS_BASE 0x1f4
#define MSR_PRMRR_PHYS_MASK 0x1f5
/* EDS vol 2 */
#define MSR_LT_MEMORY_LOCKED 0x2e7
#define MSR_MEM_LOCK_BIT1 (1 << 1)
#define MSR_MEM_LOCK_BIT2 (1 << 2)
#endif /* _SOC_MSR_H_ */

View file

@ -56,6 +56,7 @@
#define LPC_DEV 31
#define LPC_FUNC 0
#define PCH_DEVFN_LPC PCI_DEVFN(LPC_DEV, LPC_FUNC)
#define PCH_DEV_LPC PCI_DEV(BUS0, LPC_DEV, LPC_FUNC)
#define SATA_DEV 31
#define SATA_FUNC 2

View file

@ -0,0 +1,28 @@
/*
* This file is part of the coreboot project.
*
* Copyright (C) 2007-2009 coresystems GmbH
* Copyright (C) 2013 Google Inc.
* Copyright (C) 2015-2016 Intel Corp.
* Copyright (C) 2016-2018 Siemens AG
*
* 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_FSP_BROADWELL_DE_PM_H_
#define _SOC_FSP_BROADWELL_DE_PM_H_
/*
* Brings in get_pmbase so that StmPlatformResource.c can build
* under 4.11
*/
#include <soc/acpi.h>
#endif

View file

@ -13,6 +13,8 @@
* GNU General Public License for more details.
*/
#include <cpu/x86/msr.h>
#include <soc/msr.h>
#include <stddef.h>
#include <device/pci_ops.h>
#include <device/dram/ddr4.h>
@ -20,6 +22,8 @@
#include <soc/memory.h>
#include <spd_bin.h>
#define MAX_SPD_READ_TRIES 3
static uint32_t get_memory_dclk(void)
{
uint32_t reg32 =
@ -30,7 +34,7 @@ static uint32_t get_memory_dclk(void)
void save_dimm_info(void)
{
int index = 0;
uint32_t dclk_mhz = 0;
uint32_t dclk_mhz = 0, tries;
/*
* When talking to SPD chips through IMC slave offset of 0x50 is automagically added
@ -53,9 +57,39 @@ void save_dimm_info(void)
for (int slot = 0; slot < CONFIG_DIMM_MAX / IMC_MAX_CHANNELS; slot++) {
dimm_attr dimm = {0};
u8 *spd_data = blk.spd_array[index];
if (spd_decode_ddr4(&dimm, spd_data) == SPD_STATUS_OK)
spd_add_smbios17_ddr4(channel, slot, dclk_mhz, &dimm);
int res = SPD_STATUS_OK;
tries = MAX_SPD_READ_TRIES;
/*
* SMBus controller can't validate data integrity. So on CRC
* error retry a few times.
*/
do {
res = spd_decode_ddr4(&dimm, spd_data);
if (res == SPD_STATUS_CRC_ERROR) {
printk(BIOS_ERR,
"SPD CRC error, channel %u slot %u "
"try %u\n", channel, slot, tries);
get_spd_smbus(&blk);
}
} while (tries-- && res == SPD_STATUS_CRC_ERROR);
index++;
if (res == SPD_STATUS_CRC_ERROR) {
printk(BIOS_WARNING, "Gave up reading CRC on channel %u"
" slot %u\n", channel, slot);
continue;
}
if (res == SPD_STATUS_OK) {
spd_add_smbios17_ddr4(channel, slot, dclk_mhz, &dimm);
}
}
}
}
bool memory_config_is_locked(void)
{
msr_t msr = rdmsr(MSR_LT_MEMORY_LOCKED);
return (msr.lo & (MSR_MEM_LOCK_BIT1 | MSR_MEM_LOCK_BIT2));
}

View file

@ -21,8 +21,10 @@
#include <cbmem.h>
#include <console/console.h>
#include <console/usb.h>
#include <cpu/x86/msr.h>
#include <cpu/x86/mtrr.h>
#include <cpu/x86/smm.h>
#include <cf9_reset.h>
#include <program_loading.h>
#include <timestamp.h>
#include <version.h>
@ -38,6 +40,9 @@
#include <soc/ubox.h>
#include <build.h>
#include <security/intel/txt/txt.h>
#include <security/intel/txt/txt_register.h>
static void init_rtc(void)
{
u16 gen_pmcon3 = pci_read_config16(PCI_DEV(0, LPC_DEV, LPC_FUNC), GEN_PMCON_3);
@ -122,7 +127,24 @@ static void early_iio_hide(void)
iio_hide(dev);
}
}
}
static void check_msr_lock(void)
{
/*
* Sometimes the system boots in an invalid state, where random values
* have been written to MSRs and then the MSRs are locked.
* Seems to always happen on warm reset.
*
* Power cycling or a board_reset() isn't sufficient in this case, so
* issue a full_reset() to "fix" this issue.
*/
msr_t msr = rdmsr(IA32_FEATURE_CONTROL);
if (msr.lo & 1) {
console_init();
printk(BIOS_EMERG, "Detected broken platform state. Issuing full reset\n");
full_reset();
}
}
/* Entry from cache-as-ram.inc. */
@ -143,6 +165,8 @@ void *asmlinkage main(FSP_INFO_HEADER *fsp_info_header)
enable_integrated_uart(CONFIG_UART_FOR_CONSOLE);
}
check_msr_lock();
/* Call into mainboard. */
post_code(0x41);
early_mainboard_romstage_entry();
@ -156,6 +180,12 @@ void *asmlinkage main(FSP_INFO_HEADER *fsp_info_header)
early_iio_hide();
timestamp_add_now(TS_BEFORE_INITRAM);
post_code(0x48);
if (CONFIG(INTEL_TXT)) {
printk(BIOS_DEBUG, "Check TXT_ERROR register\n");
intel_txt_log_acm_error(read32((void *)TXT_ERROR));
}
/*
* Call early init to initialize memory and chipset. This function returns
* to the romstage_main_continue function with a pointer to the HOB

View file

@ -28,6 +28,7 @@
#include <pc80/i8259.h>
#include <pc80/isa-dma.h>
#include <soc/iomap.h>
#include <soc/intel/common/block/lpc/lpc_def.h>
#include <soc/irq.h>
#include <soc/lpc.h>
#include <soc/pci_devs.h>
@ -216,6 +217,17 @@ static void sc_read_resources(struct device *dev)
pci_dev_read_resources(dev);
sc_add_mmio_resources(dev);
sc_add_io_resources(dev);
const config_t *config = config_of_soc();
if (config->lpc_lgmr) {
struct resource *res;
res = new_resource(dev, LGMR);
res->base = config->lpc_lgmr & ~(LPC_LGMR_EN);
res->size = 64 * KiB;
res->flags = IORESOURCE_MEM | IORESOURCE_ASSIGNED | IORESOURCE_FIXED
| IORESOURCE_RESERVE;
pci_write_config32(dev, LGMR, config->lpc_lgmr);
}
}
static void sc_init(struct device *dev)

View file

@ -171,5 +171,8 @@ void pmc_set_disb(void);
/* Clear PMCON status bits */
void pmc_clear_pmcon_sts(void);
/* STM Support */
uint16_t get_pmbase(void);
#endif /* !defined(__ACPI__) */
#endif

View file

@ -272,3 +272,9 @@ void soc_fill_power_state(struct chipset_power_state *ps)
printk(BIOS_DEBUG, "GBLRST_CAUSE: %08x %08x\n",
ps->gblrst_cause[0], ps->gblrst_cause[1]);
}
/* STM Support */
uint16_t get_pmbase(void)
{
return (uint16_t) ACPI_BASE_ADDRESS;
}

View file

@ -104,3 +104,10 @@ void acpi_fill_in_fadt(acpi_fadt_t *fadt)
printk(BIOS_SPEW, " 0x%08x: RESET\n", fadt->reset_reg.addrl);
}
uint16_t get_pmbase(void)
{
struct device *dev = pcidev_on_root(PCI_DEVICE_NUMBER_QNC_LPC,
PCI_FUNCTION_NUMBER_QNC_LPC);
return (uint16_t) pci_read_config32(dev, R_QNC_LPC_PM1BLK) & B_QNC_LPC_PM1BLK_MASK;
}

View file

@ -27,4 +27,7 @@ struct chipset_power_state {
struct chipset_power_state *get_power_state(void);
int fill_power_state(void);
/* STM Support */
uint16_t get_pmbase(void);
#endif /* _SOC_PM_H_ */

Some files were not shown because too many files have changed in this diff Show more