Compare commits

..

No commits in common. "main" and "HEAD" have entirely different histories.

5027 changed files with 50708 additions and 258322 deletions

1
.gitignore vendored
View file

@ -35,7 +35,6 @@ tags
.cache
compile_commands.json
.vscode/
.clangd
# Cross-compile toolkits
xgcc/

11
.gitmodules vendored
View file

@ -54,7 +54,6 @@
[submodule "3rdparty/intel-sec-tools"]
path = 3rdparty/intel-sec-tools
url = https://review.coreboot.org/9esec-security-tooling.git
ignore = dirty
[submodule "3rdparty/stm"]
path = 3rdparty/stm
url = https://review.coreboot.org/STM
@ -63,19 +62,9 @@
path = util/goswid
url = https://review.coreboot.org/goswid
branch = trunk
ignore = dirty
[submodule "src/vendorcode/amd/opensil/genoa_poc/opensil"]
path = src/vendorcode/amd/opensil/genoa_poc/opensil
url = https://review.coreboot.org/opensil_genoa_poc.git
[submodule "3rdparty/open-power-signing-utils"]
path = 3rdparty/open-power-signing-utils
url = https://review.coreboot.org/open-power-signing-utils.git
[submodule "src/vendorcode/amd/opensil/phoenix_poc/opensil"]
path = src/vendorcode/amd/opensil/phoenix_poc/opensil
url = https://github.com/openSIL/openSIL.git
branch = phoenix_poc
[submodule "src/vendorcode/amd/opensil/turin_poc/opensil"]
path = src/vendorcode/amd/opensil/turin_poc/opensil
url = https://github.com/openSIL/openSIL.git
branch = turin_poc

2
3rdparty/amd_blobs vendored

@ -1 +1 @@
Subproject commit aa9288a33c6d7a67e55b8757390029207593fa9f
Subproject commit 26c572974bcf7255930b0e9a51da3144ed0104b5

@ -1 +1 @@
Subproject commit 9109143417b24337d39a2a9583828a44996f8aac
Subproject commit 15e5c6c91d483aa52908154cc80e48956e234232

2
3rdparty/blobs vendored

@ -1 +1 @@
Subproject commit 4a8de0324e7d389454ec33cdf66939b653bf6800
Subproject commit 14f8fcc1b426cb0884a21a9b715da6e0c1c7f434

2
3rdparty/fsp vendored

@ -1 +1 @@
Subproject commit 81399b3b61479abc379c2d01362d4b6dc6f515c9
Subproject commit 15c0f7b3f723bcd713e5ab11ebc502f30d9084e7

@ -1 +1 @@
Subproject commit 250941fb670645d7d91f761cc63656ad3a1ec367
Subproject commit 8ac9378a84879e81c503e09f344560b3dd7f72df

2
3rdparty/libgfxinit vendored

@ -1 +1 @@
Subproject commit 3c3828add50024e90e57d6fbe0e660d1b66302d9
Subproject commit 17cfc92f402493979783585b6581efbd98c0cf07

2
3rdparty/qc_blobs vendored

@ -1 +1 @@
Subproject commit 6379308814bd00a8b6e36a4715bdb86ba019a3a7
Subproject commit a252198ec6544e13904cfe831cec3e784aaa715d

2
3rdparty/vboot vendored

@ -1 +1 @@
Subproject commit 5c360ef458b0a013d8a6d47724bb0fffb5accbcf
Subproject commit 3f94e2c7ed58c4e67d6e7dc6052ec615dbbb9bb4

103
AUTHORS
View file

@ -15,14 +15,12 @@ Aaron Durbin
Abe Levkoy
Abel Briggs
Abhinav Hardikar
Abhishek Pandit-Subedi
AdaCore
Adam Liu
Adam Mills
Advanced Computing Lab, LANL
Advanced Micro Devices, Inc.
AG Electronics Ltd.
Agogo
Ahamed Husni
Akshu Agrawal
Al Hirani
@ -43,30 +41,24 @@ Alexey Vazhnov
Alice Sell
Alicja Michalska
Allen-KH Cheng
Alok Agarwal
Alper Nebi Yasak
Amanda Hwang
American Megatrends International, LLC
Amersel
Amit Caleechurn
Ana Carolina Cabral
Analog Devices Inc.
Analogix Semiconductor
Anand Mistry
Anand Vaikar
Anastasios Koutian
Andre
Andre Heider
Andrew McRae
Andrew SH Cheng
Andrey Pronin
Andriy Gapon
Andy
Andy Fleming
Andy Pont
Andy-ld Lu
Angel Pons
Angela Czubak
Anil Kumar K
Anna Karaś
Annie Chen
@ -76,7 +68,6 @@ Appukuttan V K
Arashk Mahshidfar
Arec Kao
Ariel Fang
Ariel Otilibili
ARM Limited and Contributors
Arthur Heymans
Asami Doi
@ -86,12 +77,9 @@ Ashqti
ASPEED Technology Inc.
Atheros Corporation
Atmel Corporation
Avi Uday
Avinash Munduru
Balaji Manigandan
Balázs Vinarz
BAP - Bruhnspace Advanced Projects
Bartłomiej Grzesik
Baruch Siach
Ben Chuang
Ben Kao
@ -102,7 +90,6 @@ Bernardo Perez Priego
Bhanu Prakash Maiya
Bill Xie
Bin Meng
Bincai Liu
Bitland Tech Inc.
Bob Moragues
Bora Guvendik
@ -110,13 +97,10 @@ Boris Barbulovski
Boris Mittelberg
Brandon Breitenstein
Brandon Weeks
Brian Hsu
Brian Norris
Bryant Ou
Carl-Daniel Hailfinger
Carlos López
Casper Chang
Cathy Xu
Caveh Jalali
Cavium Inc.
Chao Gui
@ -141,7 +125,6 @@ Cong Yang
CoolStar
coresystems GmbH
Corey Osgood
Crystal Guo
Curt Brune
Curtis Chen
Custom Ideas
@ -161,7 +144,6 @@ Dave Airlie
David Brownell
David Greenman
David Hendricks
David Li
David Lin
David Milosevic
David Mosberger-Tang
@ -171,7 +153,6 @@ David Wu
Dawei Chien
Deepika Punyamurtula
Deepti Deshatty
Dehui Sun
Denis 'GNUtoo' Carikli
Denis Dowling
DENX Software Engineering
@ -185,7 +166,6 @@ Divya S Sasidharan
Dmitry Ponamorev
Dmitry Torokhov
DMP Electronics Inc.
Dolan Liu
Dominik Behr
Donghwa Lee
Drew Eckhardt
@ -206,8 +186,6 @@ ELSOFT AG
Eltan B.V
Eltan B.V.
Elyes Haouas
Emilie Roberts
Enzo Potenza
Eran Mitrani
Eren Peng
Eric Biederman
@ -221,20 +199,17 @@ Ethan Tsao
Eugene Myers
Evan Green
Evgeny Zinoviev
Evie (Ivi) Ballou
Fabian Groffen
Fabian Kunkel
Fabian Meyer
Fabio Aiuto
Fabrice Bellard
Facebook, Inc.
Federico Amedeo Izzo
Fei Yan
Felix Friedlander
Felix Held
Felix Singer
Fengquan Chen
Filip Brozovic
Filip Lewiński
Flora Fu
Florian Laufenböck
@ -250,12 +225,8 @@ Freescale Semiconductor, Inc.
Furquan Shaikh
Gaggery Tsai
Gang C Chen
Garen Wu
Gareth Yu
Garmin Chang
Gary Jennejohn
Gavin Liu
George Burgess
George Trudeau
Gerald Van Baren
Gerd Hoffmann
@ -263,7 +234,6 @@ Gergely Kiss
Google LLC
Greg Watson
Grzegorz Bernacki
Guangjie Song
Guennadi Liakhovetski
Guodong Liu
Gwendal Grignou
@ -271,7 +241,6 @@ Hal Martin
Hao Chou
Hao Wang
HardenedLinux
Harrie Paijmans
Harsha B R
Harshit Sharma
Henry C Chen
@ -279,13 +248,11 @@ Herbert Wu
Hewlett Packard Enterprise Development LP
Hewlett-Packard Development Company, L.P.
Himanshu Sahdev
Hope Wang
Housong Zhang
Hsiao Chien Sung
Hsin-hsiung wang
Hsin-Te Yuan
Hsuan Ting Chen
Hualin Wei
Huaqin Technology Co., Ltd
Huaqin Telecom Inc.
Hui Liu
@ -300,7 +267,6 @@ Igor Pavlov
Ikjoon Jang
Imagination Technologies
Infineon Technologies
Ingo Reitz
InKi Dae
INSPUR Co., Ltd
Intel Corporation
@ -318,14 +284,11 @@ Jakub Czapiga
James Chao
James Lo
James Ye
Jameson Thies
Jamie Chen
Jamie Ryu
Jan Dabros
Jan Philipp Groß
Jan Samek
Jan Tatje
Jarried Lin
Jason Glenesk
Jason Nein
Jason V Le
@ -334,9 +297,7 @@ Jason Zhao
jason-ch chen
Jason-jh Lin
Jay Patel
Jayvik Desai
Jean Lucas
Jędrzej Ciupis
Jeff Chase
Jeff Daly
Jeff Li
@ -357,12 +318,10 @@ Jingle Hsu
Jitao Shi
Joe Pillow
Joe Tessler
Joel Bueno
Joel Kitching
Joel Linn
Joey Peng
Johanna Schander
Johannes Hahn
John Su
John Zhao
Johnny Li
@ -380,9 +339,7 @@ Jörg Mische
Joseph Smith
Josie Nordrum
Juan José García-Castro Crespo
Julia Kittlinger
Julia Tsai
Julian Intronati
Julian Schroeder
Julian Stecklina
Julien Viard de Galbert
@ -391,11 +348,9 @@ Kacper Stojek
Kaiyen Chang
Kane Chen
Kangheui Won
KangMin Wang
Kapil Porwal
Karol Zmyslowski
Karthik Ramasubramanian
Ke Zheng
Kei Hiroyoshi
Keith Hui
Keith Packard
@ -407,12 +362,10 @@ Kevin Chowski
Kevin Cody-Little
Kevin Keijzer
Kevin O'Connor
Kevin Yang
Kevin3 Yang
kewei xu
Kilari Raasi
Kirk Wang
Kiwi Liu
Konrad Adamczyk
Kontron Europe GmbH
Kornel Dulęba
@ -422,7 +375,6 @@ Kshitij
Kshitiz Godara
Kulkarni. Srinivas
Kun Liu
KunYi Chen
Kyle Lin
Kyösti Mälkki
Lance Zhao
@ -445,15 +397,10 @@ linear
Linus Torvalds
Linux Networx, Inc.
LiPPERT ADLINK Technology GmbH
Liu Liu
Liya Li
Lu Tang
Lu. Pen-ChunX
Lubomir Rintel
Luc Verhaegen
Luca Lai
Lucas Chen
Lukas Wunner
Mac Chiang
Maciej Matuszczyk
Maciej Pijanowski
@ -473,7 +420,6 @@ Mario Scheithauer
Marius Gröger
Mariusz Szafranski
Mariusz Szafrański
Mark Chang
Mark Hasemeyer
Mark Hsieh
Mars Chen
@ -484,7 +430,6 @@ Martin Roth
Marvell International Ltd.
Marvell Semiconductor Inc.
Marx Wang
Masa Nakura
Masanori Ogino
Máté Kukri
Matei Dibu
@ -493,7 +438,6 @@ Matt Chen
Matt Delco
Matt DeVillier
Matt Papageorge
Matt Turner
Matthew Blecker
Matthew Ziegelbaum
Mattias Nissler
@ -506,7 +450,6 @@ Maximilian Brune
Mediatek Inc.
MediaTek Inc.
Meera Ravindranath
Melongmelong
Meng-Huan Yu
Meta Platforms, Inc
mgabryelski1
@ -519,20 +462,15 @@ Michael Strosche
Michael Walle
Michał Kopeć
Michal Suchanek
Michał Zieliński
Michał Żygowski
Micro-Star INT'L CO., LTD.
Mika Westerberg
Mike Banon
Mike Lin
Mike Shih
Mingjin Ge
Miriam Polzer
mkurumel
Moises Garcia
Momoko Hattori
Mondrian Nuessle
Monika A
Monikaanan
MontaVista Software, Inc.
Morgan Jang
@ -542,7 +480,7 @@ mtk15698
mturney mturney
Musse Abdullahi
Myles Watson
Nancy Lin
Nancy.Lin
Naresh Solanki
Nathan Lu
Naveen R. Iyer
@ -553,14 +491,12 @@ Nicholas Sielicki
Nicholas Sudsgaard
Nick Barker
Nick Chen
Nick Kochlowski
Nick Vaccaro
Nico Huber
Nico Rikken
Nicola Corna
Nicolas Boichat
Nicole Faerber
Nigel Tao
Nikolai Vyssotski
Nils Jacobs
Nina Wu
@ -574,10 +510,6 @@ Omar Pakker
Online SAS
Opal Voravootivat
Orion Technologies, LLC
Ot_chhao.chang
Ot_hao.han
Ot_song Fan
Pablo
Pablo Ceballos
Pablo Stebler
Pan Gao
@ -607,19 +539,16 @@ Philipp Bartsch
Philipp Degler
Philipp Deppenwiese
Philipp Hug
Pierce Chou
Piotr Kleinschmidt
Po Xu
Poornima Tom
Pranava Y N
Prasad Malisetty
Prashant Malani
Pratik Vishwakarma
Pratikkumar Prajapati
Pratikkumar V Prajapati
Protectli
PugzAreCute
Purdea Andrei
Purism SPC
Purism, SPC
Qii Wang
Qinghong Zeng
@ -637,7 +566,6 @@ Ravindra
Ravishankar Sarawadi
Ray Han Lim Ng
Raymond Chung
Reagan
Red Hat, Inc
ReddestDream
Rehan Ghori
@ -655,7 +583,6 @@ Richard Woodruff
Rick Lee
Ricky Chang
Riku Viitanen
Rishika Raj
Ritul Guru
Rizwan Qureshi
Rnhmjoj
@ -675,7 +602,6 @@ Roman Zippel
Ron Lee
Ron Minnich
Ronak Kanabar
Ronald Claveau
Ronald G. Minnich
Rory Liu
Rudolf Marek
@ -697,7 +623,6 @@ Samuel Holland
Sandeep Maheswaram
Sathya Prakash M R
Satya Priya Kakitapalli
Satya SreenivasL
Saurabh Mishra
SciTech Software, Inc.
Scott Chao
@ -725,7 +650,6 @@ Shiyu Sun
Shon Wang
Shou-Chieh Hsu
Shreesh Chhabbi
Shunxi Zhang
Shuo Liu
Siemens AG
SiFive, Inc
@ -738,12 +662,10 @@ Simon Zhou
Sindhoor Tilak
Solomon Alan-Dei
Song Fan
Sowmya Aralguppe
Sridhar Siricilla
Srinidhi N Kaushik
Srinivasa Rao Mandadapu
ST Microelectronics
Stanisław Kardach
Stanley Wu
Star Labs Online Ltd
Stefan Binding
@ -771,7 +693,6 @@ Tao Xia
Tarun Tuli
Teddy Shih
Terry Chen
Terry Cheong
Texas Instruments
The Android Open Source Project
The ChromiumOS Authors
@ -790,9 +711,7 @@ Timothy Pearson
tinghan shen
Tobias Diedrich
Tom Hiller
Tomasz Michalec
Tommie Lin
Tongtong Pan
Tony Huang
Tracy Wu
Trevor Wu
@ -809,13 +728,10 @@ Usha P
Uwe Hermann
Uwe Poeche
V Sowmya
Vladimir Epifantsev
Václav Straka
Vadim Bendebury
Valentyn Sudomyr
Van Chen
Varshit B Pandya
Varun Upadhyay
Veerabhadrarao Badiganti
Venkat Thogaru
Venkata Krishna Nimmagadda
@ -824,7 +740,6 @@ Victor Ding
Vidya Gopalakrishnan
Vikram Narayanan
Vikrant L Jadeja
Vince Liu
Vinod Polimera
Vipin Kumar
Vitaly Rodionov
@ -837,10 +752,8 @@ Ward Vandewege
Wayne Wang
Weimin Wu
Weiyi Lu
Wen Zhang
Wenbin Mei
Wentao Qin
Wenzhen Yu
Werner Zeh
Wilbert Duijvenvoorde
William Wei
@ -859,16 +772,12 @@ Wonkyu Kim
Wuxy
Xiang W
Xin Ji
Xiwen Shao
Xixi Chen
Xue Yao
Xueqi Zhang
Xuxin Xiong
YADRO
Yan Liu
Yang Wu
Yann Collet
Yanqiong Huang
Yaroslav Kurlaev
YH Lin
Yidi Lin
@ -883,19 +792,14 @@ Yu-Ping Wu
Yuanliding
Yuchen He
Yuchen Huang
Yuchiche
Yunlong Jia
Yuval Peress
Zachary Yedidia
Zanxi Chen
Zebreus
Zhanyong Wang
Zhaoming Luo
Zhaoqing Jiu
Zheng Bao
Zhenguo Li
Zhi7 Li
Zhigang Qin
Zhiqiang Ma
Zhixing Ma
Zhiyong Tao
@ -904,7 +808,6 @@ Zhuohao Lee
Ziang Wang
Zoey Wu
Zoltan Baldaszti
一颗小土豆
小田喜陽彦
忧郁沙茶
陳建宏
陳建宏

View file

@ -5,7 +5,7 @@ coreboot POST Codes
This is an (incomplete) list of POST codes emitted by coreboot v4.
0x10 Entry into protected mode
0x01 Entry into 'entry16.S' reset code jumps to here
0x01 Entry into 'crt0.s' reset code jumps to here
0x11 Start copying coreboot to RAM with decompression if compressed
0x12 Copy/decompression finished jumping to RAM
0x80 Entry into coreboot in RAM

View file

@ -204,6 +204,7 @@ Spec](https://uefi.org/specifications) for details, or run the tool
* CRLF - Carriage Return, Line Feed - \\r\\n - The standard window EOL
(End-of-Line) marker.
* crt0 - [**C Run Time 0**](https://en.wikipedia.org/wiki/Crt0)
* crt0s - crt0 Source code
* CRT - [**Cathode Ray Tube**](https://en.wikipedia.org/wiki/Cathode-ray_tube)
* CSE - Intel: Converged Security Engine
* CSI - MIPI: [**Camera Serial

View file

@ -6,5 +6,91 @@ This section contains documentation about coreboot on x86 architecture.
:maxdepth: 1
x86 PAE support <pae.md>
x86_64 support <x86_64.md>
```
## State of x86_64 support
Some SOCs now support 64bit mode. Search for HAVE_X86_64_SUPPORT in Kconfig.
In order to add support for x86_64 the following assumptions were made:
* The CPU supports long mode
* All memory returned by malloc must be below 4GiB in physical memory
* All code that is to be run must be below 4GiB in physical memory
* The high dword of pointers is always zero
* The reference implementation is qemu
* x86 payloads are loaded below 4GiB in physical memory and are jumped
to in *protected mode*
## Assumptions for all stages using the reference implementation
* 0-4GiB are identity mapped using 2MiB-pages as WB
* Memory above 4GiB isn't accessible
* page tables reside in memory mapped ROM
* A stage can install new page tables in RAM
## Page tables
A `pagetables` cbfs file is generated based on an assembly file.
To generate the static page tables it must know the physical address where to
place the file.
The page tables contains the following structure:
* PML4E pointing to PDPE
* PDPE with *$n* entries each pointing to PDE
* *$n* PDEs with 512 entries each
At the moment *$n* is 4, which results in identity mapping the lower 4 GiB.
## Basic x86_64 support
Basic support for x86_64 has been implemented for QEMU mainboard target.
## Reference implementation
The reference implementation is
```{toctree}
:maxdepth: 1
QEMU i440fx <../../mainboard/emulation/qemu-i440fx.md>
QEMU Q35 <../../mainboard/emulation/qemu-q35.md>
```
## TODO
* Identity map memory above 4GiB in ramstage
## Future work
1. Fine grained page tables for SMM:
* Must not have execute and write permissions for the same page.
* Must allow only that TSEG pages can be marked executable
2. Support 64bit PCI BARs above 4GiB
3. Place and run code above 4GiB
## Porting other boards
* Fix compilation errors
* Test how well CAR works with x86_64 and paging
* Improve mode switches
## Known problems on real hardware
Running VGA rom directly fails. Yabel works fine though.
## Known bugs on KVM enabled qemu
The `x86_64` reference code runs fine in qemu soft-cpu, but has serious issues
when using KVM mode on some machines. The workaround is to *not* place
page-tables in ROM, as done in
[CB:49228](https://review.coreboot.org/c/coreboot/+/49228).
Here's a list of known issues:
* After entering long mode, the FPU doesn't work anymore, including accessing
MMX registers. It works fine before entering long mode. It works fine when
switching back to protected mode. Other registers, like SSE registers, are
working fine.
* Reading from virtual memory, when the page tables are stored in ROM, causes
the MMU to abort the "page table walking" mechanism when the lower address
bits of the virtual address to be translated have a specific pattern.
Instead of loading the correct physical page, the one containing the
page tables in ROM will be loaded and used, which breaks code and data as
the page table doesn't contain the expected data. This in turn leads to
undefined behaviour whenever the 'wrong' address is being read.
* Disabling paging in compatibility mode crashes the CPU.
* Returning from long mode to compatibility mode crashes the CPU.
* Entering long mode crashes on AMD host platforms.

View file

@ -1,109 +0,0 @@
# x86_64 architecture documentation
This section documents coreboot's x86_64 support. When enabled,
every coreboot stage is built for x86_64, contrary to UEFI's implementation
that only runs some stages in x86_64.
On UEFI the PEI phase, which is x86_32, brings up DRAM and installs
page tables for the x86_64 DXE and BDS phases.
## Toolchain requirements for x86_64 support
* The compiler must support generating code for the *large memory model*
(-mcmodel=large). It's supported since GCC 4.4.
Page tables can be used to provide security benefits, such as by marking
memory as non-executable or removing it entirely. This could be useful
for SMM to mark regular DRAM as NX.
The large memory model causes the compiler to emit 64bit addressing
instructions, which increases code size. In theory, this is roughly
made up for by the faster execution of the x86_64 code.
* All x86 coreboot stages and payloads must be loaded below 4GiB in
physical memory. When jumping to the payload coreboot will drop from
long mode back to protected mode to keep compatibility with these payloads.
## Comparison to UEFI
On UEFI the SEC and PEI phases (similar to coreboot's bootblock and romstage)
are run in x86_32 mode. The following (guessed) reasons are likely:
* There's no need for x86_64 as memory hasn't been trained yet. The whole 4GiB
address space, including CAR, memory mapped SPI flash and PCI BARs, are
accessible in x86_32.
* When the EFI specification was written compilers did not support
*large memory model*, required in CAR when using a 1:1 page mapping
* Code is 20% bigger in x86_64 due to *large memory model* where pointers and
function calls always use 8 byte addressing. However flash size was very
limited, compared to today's flash chips, when the EFI spec was written.
## Current software constraints for x86_64 support
The following constraints are coreboot limitations as it was intended to run in
protected mode only. The code still assumes 32bit pointers in some places and thus:
* The high dword of pointers must always be zero.
* All memory returned by malloc must be below 4GiB in physical memory.
* All code that is to be run must be below 4GiB in physical memory.
* CBMEM must reside below 4GiB in physical memory.
Any software within coreboot must not access memory resources above 4GiB until
end of BS_DEV_RESOURCES in ramstage. Only at that point the full memory map is
known and identity mapped.
## Supported boards
On the supported boards you can enable x86_64 compilation by setting the
Kconfig `USE_X86_64_SUPPORT`. This config option is enabled if the SOC/CPU
selects `HAVE_X86_64_SUPPORT`.
## Protected mode wrappers
On some platforms binary blobs are run to initialize parts of the hardware.
When these binary blobs have been compiled for x86_32, then coreboot must
switch to protected mode in order to call and run the blobs. Once the invoked
blobs finish running, coreboot needs to switch back to long mode.
Since every BLOB is different a SoC must be enabled to support x86_64 mode
by providing the correct wrapper around the x86_32 BLOBs.
## TODO
* Support more platforms
* Fix running VGA Option ROMs
* Fix running MRC.bin (Sandy Bridge / Haswell boards)
* Identity map memory above 4GiB in ramstage
* Fine grained page tables for SMM:
* Must not have execute and write permissions for the same page.
* Must only allow TSEG pages to be marked as executable.
* Must reside in SMRAM.
* Must be placed together with SMM rmodule.
* Support 64bit PCI BARs above 4GiB
* Jump to compatible payloads in long mode
## Porting other boards
* Fix compilation errors
* Test how well CAR works with x86_64 and paging
* Improve mode switches
* Test libgfxinit / VGA Option ROMs / FSP
## Known bugs on real hardware
According to Intel x86_64 mode hasn't been validated in CAR environments.
However, coreboot developers working on x86_64 support have tried this on
various Intel platforms, and so far haven't found any issues with CAR when
running in x86_64 mode.
## Known bugs on KVM enabled QEMU
The `x86_64` reference code runs fine in QEMU's soft-cpu, but has serious issues
when using KVM mode on some machines. This is due to various mechanisms trying
to accelerate the code execution.
Known issues in QEMU:
* After entering long mode, the FPU doesn't work anymore, including accessing
MMX registers. It works fine before entering long mode. It works fine when
switching back to protected mode. Other registers, like SSE registers, are
working fine.
* Reading from virtual memory, when the page tables are stored in ROM, causes
the MMU to abort the "page table walking" mechanism when the lower address
bits of the virtual address to be translated have a specific pattern.
Instead of loading the correct physical page, the one containing the
page tables in ROM will be loaded and used, which breaks code and data as
the page table doesn't contain the expected data. This in turn leads to
undefined behaviour whenever the 'wrong' address is being read.
* Disabling paging in compatibility mode crashes the CPU.
* Returning from long mode to compatibility mode crashes the CPU.
* Entering long mode crashes on AMD host platforms.

View file

@ -1,56 +0,0 @@
# Cross-Project Collaboration
Open source firmware has become popular and important over the last several
decades and is currently anchored in multiple key applications like industry,
automotive, infrastructure and commodity PC systems. coreboot has a
long-reaching history in all these applications and has become a vital
alternative to proprietary firmware solutions. Since coreboot itself is
minimalistic, other open source projects like SeaBIOS and flashrom help complete
the overall user experience by providing a well established way to boot into an
OS and easily reprogram the firmware on demand.
Open source projects often lack funds and are heavily dependent on volunteer
work by enthusiasts. coreboot has made its way over the many years its been
running and is now able to operate its own paid infrastructure for various
services like git, Gerrit and Jenkins, all of them are key factors for a
worldwide collaboration and project success. Other small but still important
projects do not have such resources and face infrastructure issues more often.
Furthermore, often the same people do work for different open source projects.
Therefore, it is important to support such projects where feasible.
For instance, sharing the IT infrastructure can leverage quite some synergies
as the tasks for different projects are quite similar, e.g. push code to public,
review it in Gerrit, let Jenkins do a build and report back to Gerrit or provide
a bug tracker platform where users and developers can report bugs and issues.
The coreboot project already has servers providing such services and these have
a huge amount of headroom to execute such tasks for other projects.
Additionally, the developers working on multiple projects are supported as they
can do their work with the same mindset while interfacing with common services
among different projects. This not only improves cross-project collaboration but
also does improve code quality because the developers do not have to switch
between different project setups.
Therefore, the coreboot project explicitly encourages collaboration with other
open source projects in the firmware domain. Especially the already well
established partnership with flashrom, SeaBIOS, and EM100 should continue to be
maintained further on. This includes:
* Sharing of the IT infrastructure
* Sharing the critical services like git, Gerrit, Jenkins and the bugtracker
* Sharing of the established communication methods via mailing list, Slack, IRC
or Discord
* Sharing web services for web page or wikis and blog posts
If there is interest in a collaboration, please reach out to
coreboot@coreboot.org.
The coreboot project is still responsible and in charge of its offered services
to partner projects. The technical details of the collaboration will be
discussed on a case-by-case basis with affected parties where coreboot project
infrastructure maintainers have the lead.
Note that it is expected that everyone using the coreboot services is expected
to follow coreboot code-of-conduct policies at all times. In cases where the
coreboot CoC is broken by someone working only on other projects in the coreboot
infrastructure, the coreboot leadership will work with the leadership of the
other project on the issue.

View file

@ -7,5 +7,4 @@ Code of Conduct <code_of_conduct.md>
Language style <language_style.md>
Community forums <forums.md>
coreboot at conferences <conferences.md>
Cross-Project Collaboration <cross_project_collaboration.md>
```

View file

@ -522,7 +522,7 @@ The preferred style for *long* (multi-line) comments is:
```c
/*
 * This is the preferred style for long multi-line
 * This is the preferred style for multi-line
 * comments in the coreboot source code.
 * Please use it consistently.
 *

View file

@ -348,8 +348,8 @@ commit message itself:
* Tested-by:
* Reviewed-by:
The script `util/scripts/cross-repo-cherrypick` can be used to help
automate this. Other tags such as 'Commit-Queue' can simply be removed.
The script `util/gitconfig/rebase.sh` can be used to help automate this.
Other tags such as 'Commit-Queue' can simply be removed.
* Check if there's documentation that needs to be updated to remain current
after your change. If there's no documentation for the part of coreboot

View file

@ -1,79 +0,0 @@
# Git Commit messages
There are a number of different recommendations for git commit
messages, so this is another one.
It's expected that coreboot contributors already generally understand
the idea of writing good git commit messages, so this is not trying
to go over everything again. There are other tutorials that cover that.
- [Linux Kernel tip tree Handbook](https://www.kernel.org/doc/html/latest/process/maintainer-tip.html#patch-subject)
- [How to write a Git Commit Message](https://cbea.ms/git-commit/)
## Line length
- The subject line should be <= 65 characters, with an absolute maximum
of 72 characters
- Prose in the commit message should be <= 72 characters
- If reflowing prose to 72 characters can reduce the length of the
commit message by 2 or more lines, please reflow it. Using the entire
72 characters on a line when reasonable is recommended, but not
required.
- Non-prose text in the body in the commit message does not need to be
wrapped at 72 characters. Examples: URLs, compiler output, or poetry.
## Both Subject & body
- Use the present tense. (The for loop exits too early, so ...", not
"The for loop exited too early, so ...").
- When using acronyms, make sure they're explained in the commit
message itself or in the [acronyms list](https://doc.coreboot.org/acronyms.html).
## Commit message Subject Line
- Start the subject line with a prefix denoting the area of the change.
Often part of the path can be used by that. Looking through existing
commit messages summaries with `git log --oneline ...` gives a good
idea. Because this prefix takes space used by the rest of the subject,
it should be kept short while still uniquely describing the area.
- Don't include `src/`
- Use abbreviations where possible:
- mb: mainboard
- vc: vendorcode
- Don't end the subject line with a period.
- Use the imperative mood. ("Fix whitespace", not "whitespace fixes").
## Commit Message Body
- Make sure the problem being solved by the commit is described. While
it may be obvious to the committer, it may not be obvious to others.
- When referencing other commits use a 12 character hash and the subject
(e.g. `commit XXXXXXXXXXXX ("some commit")`). However, use `CB:XXXXX`
when referring to an open or abandoned change on Gerrit.
- When using a URL in a commit message, use archive.org when possible.
URLs often get changed or go stale, so this keeps them stable.
- Make sure that all changes in a patch are addressed in the commit
message.
- A TEST= tag is highly recommended, but not required. This lets people
know whether you tested it by booting the board or just by compiling.
- All but the most trivial of patches should generally have a body.
- A BUG= tag can be added when the author wants to indicate that the
patch is or is not related to a bug. This can be either in coreboot's
issue tracker, or a private issue tracker.
- `BUG=b:####` is used by the Google internal issue tracker.
- `BUG=chromium:####` indicates the Chromium public tracker at
https://issues.chromium.org/
- `BUG=CID ####` can be used to indicate coverity error fixes.
- `BUG=https://...` can be used to link directly to a public
tracker.
- The BRANCH= tag is used in cases where a patch needs to be added to a
specific downstream branch. This is never required by the coreboot
project.
## Footers
- The Signed-off-by line is required (Jenkins forces this).
- The Change ID is required (Gerrit forces this.)
- When adding a patch that has already gone through another git or
gerrit, the footers from those previous commits may be added, but
keep the list reasonable.

View file

@ -5,25 +5,7 @@
Coding Style <coding_style.md>
Gerrit Guidelines <gerrit_guidelines.md>
Commit Message Guidelines <git_commit_messages.md>
Project Ideas <project_ideas.md>
Documentation Ideas <documentation_ideas.md>
Google Summer of Code <gsoc.md>
```
The coreboot project uses the Developer Certificate of Origin as its
policy of accepting contributions. As such, a submitter bears the burden
that they have all necessary rights to submit their contribution to the
project under the project's licenses as appropriate. Violations of third
party rights will lead to the code's removal or replacement as suitable
to bring the project back into compliance.
This applies no matter under which circumstances a contribution has been
created: legal frameworks, work contracts, Generative Artificial
Intelligence ("AI") tooling, or other aspects that may affect the
ownership and copyright status of a contribution are outside the
project's control.
See the [Sign-off procedure] for more information.
[Sign-off procedure]: gerrit_guidelines.md#sign-off-procedure

View file

@ -1,387 +0,0 @@
# ACPI Active Cooling with Five-Level Fan Control
## Overview
This document describes an ACPI-based thermal management pattern used across multiple coreboot mainboards. The implementation uses ACPI thermal zones with active cooling policies to control fan speed based on CPU temperature through a five-level power resource state machine.
This pattern is particularly prevalent on Intel-based mainboards using SuperIO environmental controllers for fan PWM control.
## Mainboards Using This Pattern
The following mainboards implement this five-level ACPI fan control pattern:
### Google Chromebooks
- **google/beltino** - Haswell Chromebox
- All variants (mccloud, monroe, panther, tricky, zako) use a single implementation
- **google/jecht** - Broadwell Chromebox
- Each variant (jecht, rikku, guado, tidus) has a unique implementation
### Samsung
- **samsung/stumpy** - Sandy Bridge Chromebox
### Intel Reference Boards
- **intel/wtm2** - Haswell ULT reference board
- **intel/baskingridge** - Haswell desktop reference board
- **intel/emeraldlake2** - Ivy Bridge reference board
## Architecture
### Hardware Components
Common hardware elements across implementations:
- **Temperature Sensor**: SuperIO TMPIN3 reads CPU temperature via PECI (Platform Environment Control Interface)
- **Fan Controller**: SuperIO Environmental Controller (ENVC) with PWM output
- Fan2 (F2PS) on Google Chromebooks
- Fan3 (F3PS) on Intel/Samsung boards
- **CPU**: Provides temperature data as an offset from Tj_max (maximum junction temperature)
### ACPI Components
- **Thermal Zone**: `\_TZ.THRM` - Main thermal management zone
- **Fan Devices**: `FAN0` through `FAN4` - Five fan speed levels
- **Power Resources**: `FNP0` through `FNP4` - Control fan state transitions
- **Active Cooling Levels**: `_AC0` through `_AC4` - Temperature thresholds for each fan level
## Fan Speed Levels
The system implements **5 fan speed levels** (0-4), where:
- **Level 0**: Maximum fan speed (highest cooling, activated at highest temperature)
- **Level 1**: High fan speed
- **Level 2**: Medium fan speed
- **Level 3**: Low fan speed
- **Level 4**: Minimum fan speed (idle/baseline cooling, default state)
The system starts at **Level 4** (minimum speed) and increases to lower-numbered levels as temperature rises.
## Temperature Management
### Temperature Reading Process
1. **Raw PECI Reading**: Read from `\_SB.PCI0.LPCB.SIO.ENVC.TIN3`
- Returns a value representing offset from Tj_max
- Value 0x80 indicates "no reading available"
- Values 0 or 255 are invalid
2. **Temperature Calculation**:
```
actual_temperature = Tj_max - (255 - raw_value)
```
3. **Conversion to ACPI Format**: Convert from Celsius to deci-Kelvin:
```
deci_kelvin = (celsius * 10) + 2732
```
### Critical Temperature Handling
Most implementations include safety logic in the `_TMP` method:
- If temperature reaches `\TMAX` (Tj_max), logs a critical event
- Waits 1 second for sensor re-poll
- Re-reads temperature to confirm
- Reports the current temperature to the OS
### Temperature Thresholds
Thresholds are defined in board-specific headers (typically `thermal.h`):
- `FAN0_THRESHOLD_ON/OFF` - Trigger points for maximum fan speed
- `FAN1_THRESHOLD_ON/OFF` - Trigger points for high fan speed
- `FAN2_THRESHOLD_ON/OFF` - Trigger points for medium fan speed
- `FAN3_THRESHOLD_ON/OFF` - Trigger points for low fan speed
- `FAN4_PWM` - PWM value for minimum fan speed
Each level has hysteresis (different ON/OFF thresholds) to prevent rapid cycling.
## Active Cooling Implementation
### Active Cooling Methods (`_ACx`)
Each `_ACx` method returns a temperature threshold:
- When system temperature **exceeds** the threshold, the OS activates the corresponding fan level
- When temperature **falls below** the threshold, the OS may deactivate that level
**Hysteresis Logic**:
```
Method (_AC0) {
If (\FLVL <= 0) {
Return (CTOK (FAN0_THRESHOLD_OFF)) // Higher temp to turn off
} Else {
Return (CTOK (FAN0_THRESHOLD_ON)) // Lower temp to turn on
}
}
```
This prevents oscillation by requiring different temperatures to activate vs. deactivate a fan level.
### Active Cooling Lists (`_ALx`)
Each `_ALx` associates a cooling threshold with a fan device:
```
Name (_AL0, Package () { FAN0 }) // FAN0 activated at _AC0 threshold
Name (_AL1, Package () { FAN1 }) // FAN1 activated at _AC1 threshold
Name (_AL2, Package () { FAN2 }) // FAN2 activated at _AC2 threshold
Name (_AL3, Package () { FAN3 }) // FAN3 activated at _AC3 threshold
Name (_AL4, Package () { FAN4 }) // FAN4 activated at _AC4 threshold
```
## Power Resource State Machine
Each fan level has an associated power resource (`FNP0` through `FNP4`) that manages state transitions.
### State Transitions
**FNP0-FNP3** (Levels 0-3):
- `_STA`: Returns 1 (ON) if `\FLVL <= level`, else 0 (OFF)
- `_ON`: Transitions **to** this level from a higher-numbered level
- `_OFF`: Transitions **away** from this level to the next higher-numbered level
Example for FNP0 (maximum cooling):
```
PowerResource (FNP0, 0, 0) {
Method (_STA) {
If (\FLVL <= 0) { Return (1) } // Active if at max cooling
Else { Return (0) }
}
Method (_ON) {
If (!_STA ()) { // If not already active
\FLVL = 0 // Set to max cooling
\_SB.PCI0.LPCB.SIO.ENVC.F2PS = FAN0_PWM // Set fan PWM
Notify (\_TZ.THRM, 0x81) // Notify thermal zone
}
}
Method (_OFF) {
If (_STA ()) { // If currently active
\FLVL = 1 // Transition to level 1
\_SB.PCI0.LPCB.SIO.ENVC.F2PS = FAN1_PWM // Set corresponding PWM
Notify (\_TZ.THRM, 0x81) // Notify thermal zone
}
}
}
```
**FNP4** (Minimum cooling - Level 4):
- `_STA`: Returns 1 if `\FLVL <= 4` (always true in normal operation)
- `_ON`: Transitions to minimum cooling state
- `_OFF`: **No-op** - This is the minimum state, cannot transition lower
### Critical: FNP4._OFF Must Be a No-Op
This is **essential for Windows compatibility**:
**Problem**: Early implementations had `_OFF` setting `\FLVL = 4` and PWM values, identical to `_ON`. This violated ACPI power resource requirements:
- After `_ON` is called, `_STA` must eventually return 1 (ON)
- After `_OFF` is called, `_STA` must eventually return 0 (OFF)
Since both methods resulted in `\FLVL = 4`, and `_STA` returns 1 when `\FLVL <= 4`, the power resource could never properly transition to OFF state.
**Solution**: Make `_OFF` a no-op since FAN4 is the minimum cooling state:
```
PowerResource (FNP4, 0, 0) {
Method (_STA) {
If (\FLVL <= 4) { Return (1) }
Else { Return (0) }
}
Method (_ON) {
If (!_STA ()) {
\FLVL = 4
\_SB.PCI0.LPCB.SIO.ENVC.F2PS = FAN4_PWM
Notify (\_TZ.THRM, 0x81)
}
}
Method (_OFF) {
// FAN4 is the minimum cooling state (idle/lowest fan speed)
// There is no lower state to transition to, so _OFF is a no-op
// to maintain proper ACPI power resource state machine semantics
}
}
```
This maintains proper ACPI state machine semantics and ensures Windows compatibility while maintaining Linux compatibility.
## Passive Cooling
In addition to active (fan-based) cooling, most implementations support passive cooling:
- `_PSV`: Returns passive cooling threshold temperature
- `_PSL`: Returns list of processors to throttle
- `_TC1`, `_TC2`: Thermal constants for passive cooling algorithm
- `_TSP`: Thermal sampling period (typically 20 deciseconds = 2 seconds)
When temperature exceeds `_PSV` threshold, the OS throttles CPUs listed in `_PSL` to reduce heat generation.
## Polling and Notification
- `_TZP`: Thermal zone polling period (typically 100 deciseconds = 10 seconds)
- OS polls `_TMP` at this interval to check temperature
- `Notify (\_TZ.THRM, 0x81)`: Thermal zone change notification
- Sent whenever fan level changes
- Tells OS to re-evaluate thermal zone immediately
## Initialization
The `_INI` method runs when the thermal zone is initialized:
```
Method (_INI) {
\FLVL = 4 // Start at minimum cooling
\_SB.PCI0.LPCB.SIO.ENVC.F2PS = FAN4_PWM // Set initial fan PWM
Notify (\_TZ.THRM, 0x81) // Initial notification
}
```
## Operating System Interaction
### Thermal Policy Flow
1. **OS boots** → Executes `_INI` → Fan starts at Level 4
2. **OS polls `_TMP`** periodically → Gets current temperature
3. **Temperature rises** → Exceeds `_AC3` threshold
4. **OS calls `FAN3._ON`** → Power resource FNP3 activated → `\FLVL = 3`
5. **Temperature continues rising** → Exceeds `_AC2` threshold
6. **OS calls `FAN2._ON`** → Power resource FNP2 activated → `\FLVL = 2`
7. **Temperature drops** → Falls below `_AC2` threshold
8. **OS calls `FAN2._OFF`**`\FLVL = 3` → Returns to Level 3
9. **Cycle continues** based on temperature changes
### Critical Temperature
If temperature reaches `_CRT` threshold:
- OS initiates emergency shutdown
- Prevents hardware damage from overheating
## Global Variables
Standard variables used across implementations:
- `\FLVL`: Current fan level (0-4)
- `\TMAX`: Maximum junction temperature (Tj_max)
- `\TCRT`: Critical shutdown temperature
- `\TPSV`: Passive cooling threshold temperature
## Configuration
Fan thresholds and PWM values are defined in board-specific headers, typically:
```
src/mainboard/<vendor>/<board>/include/thermal.h
```
or
```
src/mainboard/<vendor>/<board>/variants/<variant>/include/variant/thermal.h
```
Example configuration:
```c
#define FAN0_THRESHOLD_ON 75 // Temperature to activate max fan (°C)
#define FAN0_THRESHOLD_OFF 65 // Temperature to deactivate max fan (°C)
#define FAN0_PWM 0xFF // PWM duty cycle value (max)
#define FAN1_THRESHOLD_ON 65
#define FAN1_THRESHOLD_OFF 55
#define FAN1_PWM 0xC0
#define FAN2_THRESHOLD_ON 55
#define FAN2_THRESHOLD_OFF 45
#define FAN2_PWM 0x80
#define FAN3_THRESHOLD_ON 45
#define FAN3_THRESHOLD_OFF 35
#define FAN3_PWM 0x40
#define FAN4_PWM 0x20 // Idle fan speed
```
## Implementation Variations
While the core pattern is consistent, there are some variations:
### PWM Output Selection
- **Google boards**: Use Fan2 PWM (`F2PS`)
- **Intel/Samsung boards**: Use Fan3 PWM (`F3PS`)
### Guard Checks
Some implementations wrap state changes with `_STA()` checks:
```
Method (_ON) {
If (!_STA ()) { // Only change state if not already active
// ... state change
}
}
```
Others omit the guard and always perform the state change.
### Temperature Reading
- Most implementations read from SuperIO TMPIN3 via PECI
- Some (like intel/wtm2) use simplified stub implementations for reference
### Dynamic Thermal Tables
The google/jecht/tidus variant includes multiple thermal tables that can be switched based on system temperature sensors, allowing more sophisticated thermal management.
## Compatibility Notes
### Linux
- More lenient ACPI parser
- Tolerates minor state machine violations
- Worked with buggy FNP4._OFF implementations
### Windows
- Stricter ACPI compliance checking
- Requires proper power resource state machine behavior
- **Requires the FNP4._OFF no-op fix** to function correctly
- May disable thermal zone entirely if ACPI violations detected
## Debugging
To debug fan control issues:
1. **Check ACPI errors**: Look for thermal zone errors in OS logs
- Linux: `dmesg | grep -i acpi` or check `/sys/class/thermal/`
- Windows: Event Viewer → System → ACPI errors
2. **Monitor temperature**: Use OS tools to check `_TMP` readings
- Linux: `/sys/class/thermal/thermal_zone*/temp`
- Windows: HWiNFO64, HWMonitor
3. **Check fan level**: Monitor `\FLVL` value (ACPI debugger or custom logging)
4. **Verify thresholds**: Ensure threshold values are appropriate for the hardware
5. **Test state transitions**: Verify each fan level activates at correct temperature
6. **ACPI table inspection**: Decompile DSDT/SSDT tables with `acpidump` and `iasl` to verify implementation
## Implementation Checklist
When implementing this pattern on a new board:
- [ ] Define all 5 fan threshold pairs (ON/OFF) with appropriate hysteresis
- [ ] Define PWM values for all 5 fan levels
- [ ] Implement temperature sensor reading (typically PECI via SuperIO)
- [ ] Implement CTOK conversion method (°C to deci-Kelvin)
- [ ] Create all 5 PowerResource objects (FNP0-FNP4)
- [ ] **Critical**: Ensure FNP4._OFF is a no-op (not setting state)
- [ ] Create all 5 Fan Device objects (FAN0-FAN4) with correct `_PR0` references
- [ ] Implement _ACx methods with hysteresis logic
- [ ] Define _ALx packages linking to fan devices
- [ ] Implement _INI to set initial state
- [ ] Implement _TMP with error handling
- [ ] Define _CRT, _PSV, _PSL for critical/passive cooling
- [ ] Set appropriate _TZP polling interval
- [ ] Test on both Linux and Windows
## References
- [ACPI Specification 6.5 - Thermal Management](https://uefi.org/specs/ACPI/6.5/)
- [ACPI Specification - ThermalZone Objects](https://uefi.org/specs/ACPI/6.5/11_Thermal_Management.html)
- [ACPI Specification - PowerResource Objects](https://uefi.org/specs/ACPI/6.5/07_Power_and_Performance_Mgmt.html#power-resources)
- Intel PECI Specification
- SuperIO vendor datasheets (ITE, Nuvoton, Winbond, etc.)
## See Also
- [Intel DPTF](dptf.md) - More sophisticated Intel Dynamic Platform and Thermal Framework
- [ACPI GPIO Documentation](../acpi/gpio.md)

View file

@ -23,50 +23,6 @@ In both cases you have to add `C` structs in ramstage to describe the
option and group them together into a form. CFR objects should reside
on the heap as they can be modified to match the current boot flow.
### Overriding default values
Mainboards often want to reuse CFR objects defined in SoC or common code
but with different default values. Rather than duplicating the entire object
definition, mainboards can declare an override table that maps option names
to new default values.
**Example:** Override defaults for several SoC-defined options:
```
#include <drivers/option/cfr_frontend.h>
#include <intelblocks/pcie_rp.h>
const struct cfr_default_override mb_cfr_overrides[] = {
CFR_OVERRIDE_BOOL("s0ix_enable", false),
CFR_OVERRIDE_ENUM("pciexp_aspm", ASPM_DISABLE),
CFR_OVERRIDE_NUMBER("igd_dvmt", 64),
CFR_OVERRIDE_END
};
void mb_cfr_setup_menu(struct lb_cfr *cfr_root)
{
/* Register overrides before writing menu */
cfr_register_overrides(mb_cfr_overrides);
cfr_write_setup_menu(cfr_root, sm_root);
}
```
When the CFR system writes the setup menu, it will check the override table
for each option and use the override value if one exists. All other object
metadata (name, help text, enum values, flags) comes from the original object.
The following helper macros are available to populate the table:
- `CFR_OVERRIDE_BOOL(name, value)`
- `CFR_OVERRIDE_ENUM(name, value)`
- `CFR_OVERRIDE_NUMBER(name, value)`
- `CFR_OVERRIDE_VARCHAR(name, value)`
- `CFR_OVERRIDE_END`
Each macro encodes the override type, and the CFR backend validates that the
override type matches the original object's type. If the types do not match,
the override is ignored and a warning is printed.
### Updating CFR options
The CFR options should be updated before tables are written.
@ -78,7 +34,7 @@ coreboot table.
EMI eeprom.
```
static void update_serial(struct sm_object *new)
static void update_serial(const struct sm_object *obj, struct sm_object *new)
{
new->sm_varchar.default_value = get_emi_eeprom_vpd()->serial_number;
}
@ -94,9 +50,8 @@ static const struct sm_object serial_number = SM_DECLARE_VARCHAR({
The CFR options can have a dependency that must be evaluated at runtime by
the OS/payload that parses the CFR record and displays the UI.
By using the `WITH_DEP()` macro you can specify another numeric option that
is checked to hide the current option. The `WITH_DEP_VALUES()` macro allows
specifying one or more values that cause the dependent option to be displayed.
By using the `WITH_DEP()` macro you can specify another numberic option that
is checked to hide the current option.
**Example:** Declares a dependency from `sata_disable_port0` to `sata_enable`.
The option `sata_disable_port0` will be hidden as long as "sata_enable" is 0.
@ -121,37 +76,6 @@ static struct sm_object sata_disable_port0 = SM_DECLARE_BOOL({
}, WITH_DEP(&sata_enable));
```
**Example:** Declares a dependency from `com1_termination` to `com1_mode`.
The option `com1_termination` will only be shown if `com1_mode` is set to RS-485.
```
#define COM_MODE_DISABLED 3
#define COM_MODE_RS232 0
#define COM_MODE_RS485 1
static struct sm_object com1_mode = SM_DECLARE_ENUM({
.flags = CFR_OPTFLAG_RUNTIME,
.opt_name = "com1_mode",
.ui_name = "COM1 Mode",
.ui_helptext = NULL,
.default_value = 1,
.values = (const struct sm_enum_value[]) {
{ "Disabled", COM_MODE_DISABLED },
{ "RS-232", COM_MODE_RS232 },
{ "RS-485", COM_MODE_RS485 },
SM_ENUM_VALUE_END },
});
static struct sm_object com1_termination = SM_DECLARE_BOOL({
.flags = CFR_OPTFLAG_RUNTIME,
.opt_name = "com1_termination",
.ui_name = "Enable COM1 termination resistors",
.ui_helptext = NULL,
.default_value = false,
}, WITH_DEP_VALUES(&com1_mode, COM_MODE_RS485));
```
### Providing mainboard custom options
A mainboard that uses CFR can provide a list of custom options
@ -187,4 +111,4 @@ static const __cfr_form struct sm_obj_form southbridge = {
NULL
},
};
```
```

View file

@ -1,77 +0,0 @@
# Generating signed UEFI capsules with EDK2
coreboot can cooperate with an EDK2 payload to support firmware updates via the UEFI
ESRT/FMP capsule mechanism.
This document covers generating a *signed* capsule during the coreboot build.
At present, capsule generation requires a compatible EDK2 tree with the
corresponding payload-side changes. Upstream support is being tracked in:
https://github.com/tianocore/edk2/pull/12053
Older EDK2 trees may be missing pieces required by this integration.
## Build-time capsule generation
Enable capsule support and use an EDK2 payload:
- `CONFIG_DRIVERS_EFI_UPDATE_CAPSULES`: enable coreboot capsule update support.
- `CONFIG_DRIVERS_EFI_GENERATE_CAPSULE`: generate `build/coreboot.cap` after the ROM is finalised.
- `CONFIG_PAYLOAD_EDK2`: build an EDK2 payload.
When enabled, the coreboot build generates `build/coreboot.cap` after the ROM image is
finalised. The capsule can also be generated explicitly with `make capsule`.
Configure the FMAP allowlist embedded into the ROM as a manifest:
- `CONFIG_DRIVERS_EFI_CAPSULE_REGIONS`: whitespace-separated FMAP region allowlist embedded into
the ROM as a manifest (e.g. `COREBOOT EC`).
Configure the ESRT/FMP firmware identity used by the capsule:
- `CONFIG_DRIVERS_EFI_MAIN_FW_GUID`: GUID of the firmware
- `CONFIG_DRIVERS_EFI_MAIN_FW_VERSION`: firmware version encoded in the capsule header;
if set to `0`, derive a value from the leading `<major>.<minor>` in
`CONFIG_LOCALVERSION` when possible
- `CONFIG_DRIVERS_EFI_MAIN_FW_LSV`: lowest supported firmware version; if set to `0`,
use the resolved firmware version
Reset behavior during capsule application:
- `CONFIG_DRIVERS_EFI_CAPSULE_INITIATE_RESET`: add the capsule `InitiateReset` flag.
This is disabled by default because Linux rejects capsules with `InitiateReset` when using
`/dev/efi_capsule_loader`.
## Embedded drivers (FmpDxe in capsule)
Some EDK2 capsule update flows use an embedded `FmpDxe.efi` driver inside the capsule.
To generate capsules with an embedded `FmpDxe.efi`, enable:
- `CONFIG_DRIVERS_EFI_CAPSULE_EMBED_FMP_DXE`: embed `FmpDxe.efi` into generated capsules.
- `CONFIG_DRIVERS_EFI_CAPSULE_ACCEPT_EMBEDDED_DRIVERS`: configure the EDK2 payload to accept
capsules with embedded drivers (sets `PcdCapsuleEmbeddedDriverSupport=TRUE`).
Note: if Secure Boot is enabled, the embedded driver must be signed by a key trusted by the
running firmware, otherwise capsule processing may fail when loading the embedded driver.
## Capsule signing certificates
`GenerateCapsule` can sign the FMP payload (PKCS#7). Many platforms require signed capsules.
coreboot exposes three Kconfig options for the certificate chain:
- `CONFIG_DRIVERS_EFI_CAPSULE_SIGNER_PRIVATE_CERT`: PEM containing the signing private key and
leaf certificate
- `CONFIG_DRIVERS_EFI_CAPSULE_OTHER_PUBLIC_CERT`: PEM intermediate certificate
- `CONFIG_DRIVERS_EFI_CAPSULE_TRUSTED_PUBLIC_CERT`: PEM trusted root certificate
If a configured path is relative, it is interpreted relative to the configured EDK2 repository
inside `payloads/external/edk2/workspace`.
The defaults use the EDK2 BaseTools test certificate chain. Do not use the test keys for
production firmware updates.
To generate your own certificate chain and convert it into the required PEM files, see:
`BaseTools/Source/Python/Pkcs7Sign/Readme.md` in the EDK2 tree.

View file

@ -18,16 +18,13 @@ Some of the drivers currently available include:
```{toctree}
:maxdepth: 1
ACPI Five-Level Fan Control <acpi_fan_control.md>
CFR <cfr.md>
CFR use within coreboot <cfr_internal.md>
Intel DPTF <dptf.md>
IPMI BT (Block Transfer) <ipmi_bt.md>
IPMI KCS <ipmi_kcs.md>
SMMSTORE <smmstore.md>
SMMSTOREv2 <smmstorev2.md>
SoundWire <soundwire.md>
USB4 Retimer <retimer.md>
CBFS SMBIOS hooks <cbfs_smbios.md>
EDK2 capsule generation <efi_capsule_generation.md>
```

View file

@ -1,79 +0,0 @@
# IPMI Block Transfer (BT) driver
The driver can be found in `src/drivers/ipmi/` (same as KCS). It works with BMC
that provides a BT I/O interface as specified in the [IPMI] standard. See
"Intelligent Platform Management Interface Specification", v2.0, Rev. 1.1 for
more details on the interface and IPMI in general.
The driver detects the IPMI version and reserves the I/O space in coreboot's
resource allocator.
## For developers
To use the driver, select the `IPMI_BT` Kconfig and add the following PNP
device (in example for the BT at 0xe4):
```
chip drivers/ipmi
device pnp e4.0 on end # IPMI BT
end
```
**Note:** The I/O base address must be aligned to 4.
The following settings can be set in a device tree:
```{eval-rst}
+------------------+--------------+-------------------------------------------+
| Setting | Type/Default | Description/Purpose |
+==================+==============+===========================================+
| wait_for_bmc | | Boolean | Wait for BMC to boot. This can be used if |
| | | false | the BMC takes a long time to boot after |
| | | PoR. |
+------------------+--------------+-------------------------------------------+
| bmc_boot_timeout | | Integer | The timeout in seconds to wait for the |
| | | 0 | IPMI service to be loaded. Will be used |
| | | if wait_for_bmc is true. |
+------------------+--------------+-------------------------------------------+
```
## Debugging/testing the driver
`ipmi_sim` from [OpenIPMI] project can be used by running `ipmi_sim -d` in one
console to watch what's being sent/received and starting QEMU like this in
another console:
```
qemu-system-x86_64 \
-M q35,smm=on \
-bios build/coreboot.rom \
-chardev socket,id=ipmichr0,host=localhost,port=9002,reconnect=10 \
-device ipmi-bmc-extern,chardev=ipmichr0,id=bmc0 \
-device isa-ipmi-bt,bmc=bmc0,irq=0 \
-serial stdio
```
A simpler alternative is to use QEMU's builtin BMC simulator:
```
qemu-system-x86_64 \
-M q35,smm=on \
-bios build/coreboot.rom \
-device ipmi-bmc-sim,id=bmc0 \
-device isa-ipmi-bt,bmc=bmc0,irq=0 \
-serial stdio
```
## References
Useful links on the subject:
* README of `ipmi_sim`:
<https://github.com/wrouesnel/openipmi/blob/master/lanserv/README.ipmi_sim>
* slides about OpenIPMI:
<https://www.linux-kvm.org/images/7/76/03x08-Juniper-Corey_Minyard-UsingIPMIinQEMU.ods.pdf>
* a usage example: <https://github.com/dhilst/qemu-ipmi>
* old docs (the options are still there, but no longer have a dedicated page in
modern documentation): <https://hskinnemoen.github.io/qemu/specs/ipmi.html>
[IPMI]: https://www.intel.com/content/dam/www/public/us/en/documents/specification-updates/ipmi-intelligent-platform-mgt-interface-spec-2nd-gen-v2-0-spec-update.pdf
[OpenIPMI]: https://github.com/wrouesnel/openipmi

View file

@ -74,30 +74,19 @@ has to read the coreboot table with tag `0x0039`, containing:
struct lb_smmstorev2 {
uint32_t tag;
uint32_t size;
uint32_t num_blocks; /* Number of writable blocks in SMM */
uint32_t block_size; /* Size of a block in byte. Default: 64 KiB */
uint32_t mmap_addr_deprecated; /* 32-bit MMIO address of the store for read only access.
Prefer 'mmap_addr' for new software.
Zero when the address won't fit into 32-bits. */
uint32_t com_buffer; /* Physical address of the communication buffer */
uint32_t com_buffer_size; /* Size of the communication buffer in bytes */
uint8_t apm_cmd; /* The command byte to write to the APM I/O port */
uint8_t unused[3]; /* Set to zero */
uint64_t mmap_addr; /* 64-bit MMIO address of the store for read only access.
Introduced after the initial implementation. Users of
this table must check the 'size' field to detect if its
written out by coreboot. */
uint32_t num_blocks; /* Number of writeable blocks in SMM */
uint32_t block_size; /* Size of a block in byte. Default: 64 KiB */
uint32_t mmap_addr; /* MMIO address of the store for read only access */
uint32_t com_buffer; /* Physical address of the communication buffer */
uint32_t com_buffer_size; /* Size of the communication buffer in byte */
uint8_t apm_cmd; /* The command byte to write to the APM I/O port */
uint8_t unused[3]; /* Set to zero */
};
```
The absence of this coreboot table entry indicates that there's no
SMMSTOREv2 support.
`mmap_addr` is an optional field added after the initial implementation.
Users of this table must check the size field to know if it's written by coreboot.
In case it's not present 'mmap_addr_deprecated' is to be used as the SPI ROM MMIO
address and it must be below 4 GiB.
### Blocks
The SMMSTOREv2 splits the SMMSTORE FMAP partition into smaller chunks
@ -208,45 +197,6 @@ coreboot tables, there's no risk that a malicious application capable
of issuing SMIs could extract arbitrary data or modify the currently
running kernel.
## Capsule update API
Availability of this command is tied to `CONFIG_DRIVERS_EFI_UPDATE_CAPSULES`.
To allow updating full flash content (except if locked at hardware
level), few new calls were added. They reuse communication buffer, SMI
command, return values and calling arguments of SMMSTORE commands listed
above, with the exception of subcommand passed via `%ah`. If the
subcommand is to operate on full flash size, it has the highest bit set,
e.g. it is `0x85` for `SMMSTORE_CMD_RAW_READ` and `0x86` for
`SMMSTORE_CMD_RAW_WRITE`. Every `block_id` describes block relative to
the beginning of a flash, maximum value depends on its size.
Attempts to write the protected memory regions can lead to undesired
consequences ranging from system instability to bricking and security
vulnerabilities. When this feature is used, care must be taken to temporarily
lift protections for the duration of an update when the whole flash is
rewritten or the update must be constrained to affect only writable portions of
the flash (e.g., "BIOS" region).
There is one new subcommand that must be called before any other subcommands
with highest bit set can be used.
### - SMMSTORE_CMD_USE_FULL_FLASH = 0x80
This command can only be executed once and is done by the firmware.
Calling this function at runtime has no effect. It takes one additional
parameter that, contrary to other commands, isn't a pointer. Instead,
`%ebx` indicates requested state of full flash access. If it equals 0,
commands for accessing full flash are permanently disabled, otherwise
they are permanently enabled until the next boot.
The assumption is that if capsule updates are enabled at build time and
whole flash access is enabled at runtime, a UEFI payload (highly likely
EDK2 or its derivative) won't allow a regular OS to boot if the handler is
enabled without rebooting first. There could be a way of deactivating the
handler, but coreboot, having no way of enforcing its usage, might as well
permit access until a reboot and rely on the payload to do the right thing.
## External links
* [A Tour Beyond BIOS Implementing UEFI Authenticated Variables in SMM with EDK II](https://github.com/tianocore-docs/Docs/raw/master/White_Papers/A_Tour_Beyond_BIOS_Implementing_UEFI_Authenticated_Variables_in_SMM_with_EDKII_V2.pdf)

View file

@ -41,7 +41,7 @@ The bootblock loads the romstage or the verstage if verified boot is enabled.
### Cache-As-Ram
The *Cache-As-Ram*, also called Non-Eviction mode, or *CAR* allows to use the
CPU cache like regular SRAM. This is particularly useful for high level
CPU cache like regular SRAM. This is particullary useful for high level
languages like `C`, which need RAM for heap and stack.
The CAR needs to be activated using vendor specific CPU instructions.

View file

@ -75,7 +75,9 @@ $(call add_intermediate, add_mrc_data)
Note that the second line must start with a tab, not spaces.
See also <project:../tutorial/managing_local_additions.md>.
```{eval-rst}
See also :doc:`../tutorial/managing_local_additions`.
```
#### FMAP region support
With the addition of FMAP flash partitioning support to coreboot, there was a

View file

@ -1,361 +0,0 @@
# CBMEM high table memory manager
## Introduction
CBMEM (coreboot memory) is a dynamic memory infrastructure used in
coreboot to store runtime data structures, logs, and other information
that needs to persist across different boot stages, and even across warm
boots. CBMEM is crucial for maintaining state and information through
the coreboot boot process.
Its key responsibilities include:
- Providing a stable storage area for critical boot data
- Managing console logging
- Storing configuration tables for hand off to payloads
- Maintaining timestamps for performance analysis
- Preserving boot state during S3 suspend/resume cycles
- Storing data such as ACPI tables, SMBIOS tables and coreboot tables
which are used at runtime
## Creation and Placement
CBMEM is initialized by coreboot during romstage, but is used mainly in
ramstage for storing any data that needs to be saved for more than a
short period of time.
For 32-bit builds, CBMEM is typically located at the highest usable DRAM
address below the 4GiB boundary. For 64-bit builds, while there is no
strict upper limit, it is advisable to follow the same guidelines to
prevent access or addressing issues. Regardless of the build type, the
CBMEM address must remain consistent between romstage and ramstage.
Each platform may need to implement its own method for determining the
`cbmem_top` address, as this can depend on specific hardware
configurations and memory layouts.
## Architecture Overview
Each CBMEM region is identified by a unique ID, allowing different
components to store and retrieve their data during runtime.
Upon creating an entry, a block of memory of the requested size is
allocated from the reserved CBMEM region. This region typically persists
across warm reboots, making it useful for debugging and passing
information to payloads.
CBMEM is implemented as a specialized in-memory database (IMD) system
that grows downward from a defined upper memory limit. This means that
only the latest added entry may be removed.
```text
High Memory
+----------------------+ <- cbmem_top
| Root Pointer |
|----------------------|
| Root Structure |
|----------------------|
| Entry 1 |
|----------------------|
| Entry 2 |
|----------------------|
| ... |
| (grows downward) |
+----------------------+
```
### Core Components
The CBMEM system consists of several key components:
1. **Root Pointer**: Located at the very top of CBMEM memory space,
contains a magic number and offset to the Root Structure
2. **Root Structure**: Contains metadata about the CBMEM region,
including:
- Entry alignment requirements
- Maximum number of entries
- Current number of entries
- Address of the lowest allocated memory
3. **Entries**: Individual allocations within CBMEM, identified by:
- 32-bit ID (often encoding ASCII characters for readability)
- Size information
- Magic validation value
4. **IMD Implementation**: The underlying memory management system
that handles allocation, deallocation, and entry management
## Memory Layout and Initialization
CBMEM is positioned at the top of available system RAM, typically
just below the 4GiB boundary for 32-bit builds. This placement
ensures compatibility with legacy code while allowing CBMEM to
retain its contents across warm resets.
### CBMEM Location Determination
Each platform must implement a `cbmem_top_chipset()` function
that returns the physical address where CBMEM should be located.
This address must be consistent across coreboot stages and is
determined based on:
- Available physical memory
- Architecture-specific constraints
- BIOS/chipset requirements
### Initialization Process
CBMEM is initialized in a multi-step process:
1. **Early Initialization**: A small console buffer is created in during
bootblock and romstage
2. **RAM Initialization**: The full CBMEM area is established in
ramstage
3. **Normal Operation**:
- In a normal boot, CBMEM is created fresh
- Size and alignment values are specified
- Initial entries are allocated
4. **Recovery Operation**:
- During S3 resume, CBMEM structure is recovered from memory
- Content is validated using magic numbers and checksums
- All existing entries remain accessible
## Entry Management
CBMEM entries are identified by a 32-bit ID, often encoding ASCII
characters to indicate their purpose (for example, "CNSL" for console).
### Entry Creation
```c
void *cbmem_add(u32 id, u64 size);
```
This function:
- Searches for an existing entry with the given ID
- If found, returns the existing entry (size is ignored)
- If not found, allocates a new entry of the requested size
- Returns a pointer to the entry's data area
### Entry Access
```c
void *cbmem_find(u32 id);
```
This function:
- Searches for an entry with the specified ID
- Returns a pointer to the entry's data area if found
- Returns NULL if the entry does not exist
### Entry Removal
```c
int cbmem_entry_remove(const struct cbmem_entry *entry);
```
This function:
- Removes the specified entry if it was the last one added
- Returns 0 on success, negative value on failure
- Note: Due to the downward-growing design, only the most recently
added entry can be removed
## CBMEM Console Implementation
The CBMEM console is a circular buffer used for capturing log messages
across all boot stages. It is one of the most widely used CBMEM
features. The size of this buffer is determined by the
`CONFIG_CBMEM_CONSOLE_SIZE` Kconfig option.
### Console Structure
```c
struct cbmem_console {
u32 size; // Size of the buffer
u32 cursor; // Current write position and flags
u8 body[]; // Actual data buffer
};
```
Key features:
- The high bit of `cursor` indicates overflow condition
- Only the lower 28 bits of `cursor` are used as position
- Supports ring-buffer operation when full
### Console Operation
1. **Initialization**: A console entry is created in CBMEM with ID
`CBMEM_ID_CONSOLE` (0x434f4e53 - 'CONS')
2. **Writing**: Log messages are written byte-by-byte using
`cbmemc_tx_byte()` which:
- Adds data to the current cursor position
- Advances the cursor
- Sets the overflow flag when wrapping around
3. **Stage Transition**: When transitioning between boot stages:
- Pre-RAM console contents are copied to the main CBMEM console
- Any overflow condition is preserved and noted
- The process ensures no log messages are lost
## Common CBMEM Entry Types
CBMEM contains various data structures used by different coreboot
components:
- **Console**: Log messages from all boot stages (`CBMEM_ID_CONSOLE`)
- **Timestamps**: Performance metrics (`CBMEM_ID_TIMESTAMP`)
- **ACPI Tables**: ACPI data for OS handoff (`CBMEM_ID_ACPI`)
- **coreboot Tables**: System information (`CBMEM_ID_CBTABLE`)
- **Memory Information**: RAM configuration (`CBMEM_ID_MEMINFO`)
- **Stage Cache**: Code/data for faster S3 resume
- **ROM/CBFS Cache**: Cached ROM content
- **Vendor-specific**: Platform-dependent structures
A complete list of IDs is defined in
`src/commonlib/bsd/include/commonlib/bsd/cbmem_id.h`.
## Integration with Boot Stages
CBMEM interacts differently with each coreboot boot stage.
### Bootblock/Romstage
- Uses cache-as-RAM for temporary console storage
- Limited CBMEM functionality before RAM initialization
- Sets up initial timestamp entries
### Ramstage
- Full CBMEM initialization or recovery
- All entries become accessible
- Most coreboot subsystems interact with CBMEM
- Console logging is fully operational
### Payload Handoff
- CBMEM contents are preserved when transferring to the payload
- Entries are made available via coreboot tables
- Common payloads (SeaBIOS, GRUB, etc.) can access CBMEM data
## Platform-Specific Considerations
Different platforms have unique requirements for CBMEM implementation.
### x86 Platforms
- CBMEM typically located just below 4GiB
- Often integrates with ACPI resume and SMM operations
- May need to accommodate memory reserved by legacy components
### ARM/RISC-V Platforms
- More flexibility in CBMEM placement
- Must coordinate with platform-specific memory controllers
- Memory topology can vary significantly between implementations
## CBMEM Hooks
CBMEM provides a hook mechanism to allow subsystems to perform
initialization or recovery operations when CBMEM becomes available:
```c
CBMEM_CREATION_HOOK(hook_function); // First-time creation only
CBMEM_READY_HOOK(hook_function); // Any CBMEM initialization
CBMEM_READY_HOOK_EARLY(hook_function); // Early CBMEM initialization
```
These macros register functions to be called when CBMEM is initialized,
allowing components to set up their CBMEM entries at the appropriate time.
## Debugging and Utilities
### CBMEM Utility
The `cbmem` utility provides direct access to CBMEM contents on a
running system. It needs to be built from the coreboot source tree using
`make -C util/cbmem`. Common uses include:
- Listing all CBMEM entries (`cbmem -l`)
- Viewing console logs (`cbmem -c`)
- Analyzing timestamps (`cbmem -t`)
- Extracting specific entries by ID (`cbmem -e <ID>`)
### Debugging Techniques
- CBMEM console contents can be dumped to UART for debugging if serial
output is enabled.
- The console overflow flag (`cbmem -c` output) helps identify if logs
were truncated.
- Size validation within CBMEM helps detect potential memory corruption.
- Magic numbers provide integrity validation for CBMEM structures.
- Enabling `CONFIG_CBMEM_CHECKS` in Kconfig adds extra sanity checks
that can help catch issues during development.
## Limitations
While CBMEM is a powerful tool, it has some inherent limitations:
- **Downward Growth**: The stack-like allocation (growing downwards)
means that only the most recently added entry can be removed. This
prevents fragmentation but limits flexibility in freeing memory.
- **Fixed Size**: Once CBMEM is initialized in ramstage, its total size
and top address (`cbmem_top`) are fixed. Entries cannot be resized
after allocation.
- **Platform Complexity**: Determining the correct `cbmem_top` can be
complex on some platforms due to varying memory maps and reserved
regions.
## Best Practices for Developers
When working with the CBMEM subsystem:
1. **Alignment**: Always respect the alignment requirements of the
CBMEM tier (`IMD_ROOT` vs `IMD_SMALL`) you are using.
2. **ID Selection**: Use unique, meaningful IDs for new entries,
preferably encoding ASCII characters for readability (see
`cbmem_id.h`).
3. **Size Estimation**: Allocate sufficient space initially, as
entries cannot be resized.
4. **Memory Conservation**: Be mindful of limited memory resources,
especially on constrained platforms. Avoid storing excessively large
data structures in CBMEM unless necessary.
5. **Persistence**: Remember that CBMEM contents persist across
warm reboots (like S3 resume) but not across full system resets
(cold boots).
6. **Entry Ordering**: Consider that only the most recently added
entry can be removed, which might influence your allocation strategy
if you anticipate needing to free space.

View file

@ -10,6 +10,5 @@ Kconfig <kconfig.md>
Writing Documentation <writing_documentation.md>
Setting up GPIOs <gpio.md>
Adding devices to a device tree <devicetree.md>
CBMEM <cbmem.md>
Frequently Asked Questions <faq.md>
```

View file

@ -14,13 +14,18 @@ coreboot uses [Sphinx] documentation tool. We prefer the markdown format
over reStructuredText so only embedded ReST is supported. Checkout the
[Markdown Guide] for more information.
### Option 1: Use the docker image
### option 1: Use the docker image
The easiest way to build the documentation is using a docker image.
To build the image run the following in the base directory:
make -C util/docker/ doc.coreboot.org
Before building the documentation make sure the output directory is given
the correct permissions before running docker.
mkdir -p Documentation/_build
To build the documentation:
make -C util/docker docker-build-docs
@ -31,29 +36,30 @@ To have the documentation build and served over a web server live run:
On the host machine, open a browser to the address <http://0.0.0.0:8000>.
### Option 2: Install Sphinx
### option 2: Install Sphinx
Please follow this official [guide] to install sphinx. You will also need
myst-parser for sphinx to be able to handle markdown documentation.
Please follow this official [guide] to install sphinx.
You will also need python-recommonmark for sphinx to be able to handle
markdown documentation.
Since some Linux distributions don't package every needed sphinx extension,
the installation via pip in a venv is recommended. You'll need these python3
modules:
* sphinx
* myst-parser
* sphinx-rtd-theme
* recommonmark
* sphinx_rtd_theme
The following combination of versions has been tested: sphinx 8.1.3,
myst-parser 4.0.0, and sphinx-rtd-theme 2.0.0.
The following combination of versions has been tested: sphinx 2.3.1,
recommonmark 0.6.0, and sphinx_rtd_theme 0.4.3.
Now change into the `Documentation` folder in the coreboot directory and run
this command in there
make
make sphinx
If no error occurs, you can find the generated HTML documentation in
`Documentation/_build/html` now.
`Documentation/_build` now.
### Optional
@ -82,17 +88,15 @@ Documentation:
12. Shouldn't cover implementation details; for details, the code is the
reference.
## Referencing markdown documents
Starting with Sphinx 1.6 recommonmark's *auto_doc_ref* feature is broken.
To reference documents use the TOC tree or inline RST code.
## Markdown and Tables
Markdown tables are supported:
| Header 1 | Header 2 | Header 3 |
|------------|-----------|-----------|
| body row 1 | column 2 | column 3 |
| body row 2 | column 2 | column 3 |
Tables can also be written using embedded reStructured Text, which provides
additional features like the ability to merge cells:
Under Sphinx markdown tables are not supported. Therefore you can use following
code block to write tables in reStructuredText and embed them into the markdown:
```{eval-rst}
+------------+------------+-----------+
@ -113,20 +117,22 @@ additional features like the ability to merge cells:
To make sure that all documents are included into the final documentation, you
must reference each document from at least one *toctree*. The *toctree* must
only reference files in the same folder or in subfolders !
To create a toctree, you must use the following syntax to invoke the
Sphinx toctree directive:
To create a toctree, simply use a bullet list or numbered list with a single
reference. References in regular text aren't considered as *toctree* .
This feature is enabled by recommonmark's *enable_auto_toc_tree* .
**Example toctree:**
```{toctree}
:maxdepth: 1
```
* [Chapter 1](chapter1.md)
* [Chapter 2](chapter2.md)
* [Subchapter](sub/index.md)
```
Chapter 1 <chapter1.md>
Chapter 2 <chapter2.md>
Subchapter <sub/index.md>
```
References in regular text aren't considered as *toctree* .
```
1. [Chapter 1](chapter1.md)
2. [Chapter 2](chapter2.md)
```
If you do only reference the document, but do not include it in any toctree,
you'll see the following warning:
@ -146,9 +152,11 @@ readable tables, using the following reStructuredText snipped:
Of course this can only be done from a markdown file that is included in the
TOC tree.
[sphinx-autobuild]: https://github.com/sphinx-doc/sphinx-autobuild
[guide]: https://www.sphinx-doc.org/en/master/usage/installation.html
[Sphinx]: https://www.sphinx-doc.org/en/master/
[coreboot]: https://coreboot.org
[Documentation]: https://review.coreboot.org/cgit/coreboot.git/tree/Documentation
[sphinx-autobuild]: https://github.com/GaretJax/sphinx-autobuild
[guide]: http://www.sphinx-doc.org/en/stable/install.html
[Sphinx]: http://www.sphinx-doc.org/en/master/
[Markdown Guide]: https://www.markdownguide.org/
[Gerrit Guidelines]: ../contributing/gerrit_guidelines.md
[review.coreboot.org]: https://review.coreboot.org

View file

@ -22,14 +22,14 @@ GMA: Framebuffer Configuration
*coreboot* supports two different framebuffer setups. The default
enables the legacy VGA plane in textmode. Due to legacy hardware
constraints, only the first found display is enabled in this mode.
(cf. `src/drivers/intel/gma/text_fb/gma-gfx_init.adb`).
(cf. `src/drivers/intel/gma/text_fb/gma.adb`).
The second option sets up a high-resolution framebuffer with the
native resolution of the display if only one is detected, or the
smallest of all resolutions (per dimension) if multiple displays
are detected. This option is selected by
`CONFIG_FRAMEBUFFER_KEEP_VESA_MODE`.
(cf. `src/drivers/intel/gma/hires_fb/gma-gfx_init.adb`).
(cf. `src/drivers/intel/gma/hires_fb/gma.adb`).
In any case, a smaller framebuffer is up-scaled to each display's
native resolution while keeping aspect ratio.

View file

@ -219,7 +219,6 @@ Community <community/index.md>
Payloads <payloads.md>
Distributions <distributions.md>
Technotes <technotes/index.md>
Internal APIs & Configuration <internals/index.md>
ACPI <acpi/index.md>
Native Graphics Initialization with libgfxinit <gfx/libgfxinit.md>
Display panel <gfx/display-panel.md>

View file

@ -1,537 +0,0 @@
# The `chip_operations` Structure in coreboot
## Introduction
The `chip_operations` structure is a fundamental component of coreboot's
chipset abstraction layer. It provides a standardized interface for chipset-
specific code to interact with coreboot's device initialization framework.
This structure enables coreboot to support a wide variety of chipsets
while maintaining a consistent initialization flow across different hardware
platforms.
In coreboot's architecture, a "chip" refers to a collection of hardware
components that form a logical unit, such as a System-on-Chip (SoC),
a CPU, or a distinct southbridge/northbridge. The `chip_operations`
structure provides the hooks necessary for coreboot to discover, configure,
and initialize these components during the boot process.
The `chip_operations` structure is particularly crucial for the ramstage
portion of coreboot, where it connects the static device tree definitions
with the actual hardware initialization code. It serves as the bridge
between the declarative device descriptions and the imperative code that
brings those devices to life.
## Structure Definition
The `chip_operations` structure is defined in `src/include/device/device.h`
as follows:
```c
struct chip_operations {
void (*enable_dev)(struct device *dev);
void (*init)(void *chip_info);
void (*final)(void *chip_info);
unsigned int initialized : 1;
unsigned int finalized : 1;
const char *name;
};
```
### Field Descriptions
- **enable_dev**: A function pointer that takes a `struct device*`
parameter. This function is called for each device associated with the
chip during the device enumeration phase (specifically, within the
`scan_bus` operations triggered by `dev_enumerate`). Its primary
purpose is to set up device operations (`dev->ops`) based on the
device's role in the system.
- **init**: A function pointer that takes a `void*` parameter pointing to
the chip's configuration data (typically cast to a chip-specific struct).
This function is called during the chip initialization phase
(`BS_DEV_INIT_CHIPS`), before device enumeration. It usually performs
early hardware setup needed before individual devices can be configured.
- **final**: A function pointer that takes a `void*` parameter pointing to
the chip's configuration data (typically cast to a chip-specific struct).
This function is called during the final table writing phase of coreboot
initialization (`BS_WRITE_TABLES`), after all devices have been
initialized. It performs any necessary cleanup or late initialization
operations.
- **initialized**: A bit flag indicating whether the chip's init function
has been called.
- **finalized**: A bit flag indicating whether the chip's final function
has been called.
- **name**: A string containing the human-readable name of the chip, used
for debugging and logging purposes.
## Initialization Sequence and `chip_operations`
The `chip_operations` structure integrates with coreboot's boot state
machine, which is defined in `src/lib/hardwaremain.c`. The functions in
this structure are called at specific points during the boot process:
1. **BS_DEV_INIT_CHIPS** state: The `init` function is called for each
chip in the device tree. This is handled by `dev_initialize_chips()`
which iterates through all devices, identifies unique chip instances,
and invokes their `init` functions.
2. **BS_DEV_ENUMERATE** state: During the execution of this state,
`dev_enumerate()` is called, which triggers bus scanning
(e.g., `pci_scan_bus`). Within these scan routines, the `enable_dev`
function is called for devices associated with a chip. This commonly
assigns the appropriate `device_operations` structure to each device
based on its type and purpose.
3. **BS_WRITE_TABLES** state: The `final` function is called for each
chip by `dev_finalize_chips()` after all devices have been initialized
and just before payloads are loaded.
This sequence ensures that chips can perform necessary setup before their
individual devices are configured, and also perform cleanup or finalization
after all devices have been initialized but before the final tables are
written and the payload is executed.
## Relationship Between `chip_operations` and `device_operations`
It's important to understand the distinction and relationship between
`chip_operations` and `device_operations`:
- **chip_operations**: Operates at the chipset or SoC level, providing
hooks for chip-wide initialization. It's responsible for the overall
setup of a collection of devices that belong to the same logical chip.
- **device_operations**: Operates at the individual device level,
providing functions to manage specific devices within a chip. These
operations include resource allocation, device initialization, and device-
specific functionality.
The key relationship is that `chip_operations.enable_dev` is typically
responsible for assigning the appropriate `device_operations` structure
to each device based on its type and function. This is where the bridge
between the chip-level and device-level abstractions occurs.
For example, a typical implementation of the `enable_dev` function might
look like this:
```c
static void soc_enable(struct device *dev)
{
if (dev->path.type == DEVICE_PATH_DOMAIN)
dev->ops = &pci_domain_ops;
else if (dev->path.type == DEVICE_PATH_CPU_CLUSTER)
dev->ops = &cpu_bus_ops;
else if (dev->path.type == DEVICE_PATH_GPIO)
block_gpio_enable(dev);
else if (dev->path.type == DEVICE_PATH_PCI &&
dev->path.pci.devfn == PCH_DEVFN_PMC)
dev->ops = &pmc_ops;
}
```
This function examines each device's path type and assigns the appropriate
operations based on the device's role in the system.
## Integration with the Devicetree
The `chip_operations` structure is tightly integrated with coreboot's
devicetree mechanism. The devicetree is a hierarchical description of the
hardware platform, defined in `.cb` files (typically `chipset.cb`,
`devicetree.cb`, and optionally `overridetree.cb`).
In the devicetree, a `chip` directive starts a collection of devices
associated with a particular chip driver. The path specified with the
`chip` directive corresponds to a directory in the coreboot source tree
that contains the chip driver code, including a `chip.c` file that defines
the `chip_operations` structure for that chip.
For example, a devicetree might contain:
```
chip soc/intel/cannonlake
device domain 0 on
device pci 00.0 on end # Host Bridge
device pci 12.0 on end # Thermal Subsystem
# ... more devices ...
end
end
```
This connects the devices under this chip directive with the
`chip_operations` structure defined in
`src/soc/intel/cannonlake/chip.c`:
```c
struct chip_operations soc_intel_cannonlake_ops = {
.name = "Intel Cannonlake",
.enable_dev = &soc_enable,
.init = &soc_init_pre_device,
};
```
During coreboot's build process, the `sconfig` utility processes the
devicetree files and generates code that links the devices defined in the
devicetree with their corresponding `chip_operations` structures.
## Chip Configuration Data
Each chip typically defines a configuration structure in a `chip.h` file
within its source directory. This structure contains configuration settings
that can be specified in the devicetree using `register` directives.
For example, a chip might define a configuration structure like:
```c
/* In src/soc/intel/cannonlake/chip.h */
struct soc_intel_cannonlake_config {
uint8_t pcie_rp_aspm[CONFIG_MAX_ROOT_PORTS];
uint8_t usb2_ports[16];
uint8_t usb3_ports[10];
/* ... more configuration options ... */
};
```
In the devicetree, you would configure these options using register
directives:
```
chip soc/intel/cannonlake
register "pcie_rp_aspm[0]" = "ASPM_AUTO"
register "usb2_ports[5]" = "USB2_PORT_MID(OC_SKIP)"
# ... more register settings ...
device domain 0 on
# ... devices ...
end
end
```
These configuration values are made available to the chip's `init` and
`final` functions through the `chip_info` parameter, which points to
an instance of the chip's configuration structure (after appropriate
casting from `void *`).
## Implementation Examples
### Minimal Implementation
Some chips may not need extensive initialization and can provide a
minimal implementation of the `chip_operations` structure:
```c
struct chip_operations soc_ucb_riscv_ops = {
.name = "UCB RISC-V",
};
```
This implementation only provides a name for debugging purposes but
doesn't define any initialization functions.
### Basic Implementation with Initialization
A more typical implementation includes at least initialization hooks:
```c
struct chip_operations soc_amd_genoa_poc_ops = {
.name = "AMD Genoa SoC Proof of Concept",
.init = soc_init,
.final = soc_final,
};
```
The `init` function might perform chip-wide initialization:
```c
static void soc_init(void *chip_info)
{
default_dev_ops_root.write_acpi_tables = soc_acpi_write_tables;
amd_opensil_silicon_init();
data_fabric_print_mmio_conf();
fch_init(chip_info);
}
```
### Complete Implementation
A complete implementation includes all three function pointers:
```c
struct chip_operations soc_intel_xeon_sp_cpx_ops = {
.name = "Intel Cooper Lake-SP",
.enable_dev = chip_enable_dev,
.init = chip_init,
.final = chip_final,
};
```
The `enable_dev` function would typically assign device operations
based on device types:
```c
static void chip_enable_dev(struct device *dev)
{
/* PCI root complex */
if (dev->path.type == DEVICE_PATH_DOMAIN)
dev->ops = &pci_domain_ops;
/* CPU cluster */
else if (dev->path.type == DEVICE_PATH_CPU_CLUSTER)
dev->ops = &cpu_cluster_ops;
/* PCIe root ports */
else if (dev->path.type == DEVICE_PATH_PCI &&
PCI_SLOT(dev->path.pci.devfn) == PCIE_PORT1_SLOT)
dev->ops = &pcie_rp_ops;
/* ... other device types ... */
}
```
### Mainboard Implementation
It's also common for the mainboard-specific code (e.g.,
`src/mainboard/vendor/board/mainboard.c`) to define its own
`chip_operations`, often named `mainboard_ops`. The `mainboard_ops.init`
can perform early board-level setup, and `mainboard_ops.enable_dev` can
assign operations for devices specific to the mainboard or set default
operations.
```c
/* Example from src/mainboard/google/zork/mainboard.c */
struct chip_operations mainboard_ops = {
.enable_dev = mainboard_enable,
.init = mainboard_init,
.final = mainboard_final,
};
```
## Device Registration and Discovery
The `chip_operations` structure plays a key role in device registration
and discovery within coreboot. Here's how it fits into this process:
1. **Static Device Definition**: Devices are statically defined in the
devicetree files (`chipset.cb`, `devicetree.cb`, `overridetree.cb`).
2. **Code Generation**: The `sconfig` utility processes these files and
generates code in `build/static.c` that creates the device structures
and links them to their corresponding chip configuration data.
3. **Chip Initialization**: During the `BS_DEV_INIT_CHIPS` boot state,
`dev_initialize_chips()` calls each chip's `init` function to perform
chip-wide setup.
4. **Device Enumeration and Enabling**: During the `BS_DEV_ENUMERATE`
boot state, `dev_enumerate()` initiates bus scanning. The scan
functions call the associated chip's `enable_dev` function for each
device, which assigns the appropriate device operations (`dev->ops`).
5. **Device Configuration and Initialization**: Subsequent boot states
(`BS_DEV_RESOURCES`, `BS_DEV_ENABLE`, `BS_DEV_INIT`) configure and
initialize the devices according to their assigned device operations.
6. **Chip Finalization**: After all devices have been initialized,
`dev_finalize_chips()` calls each chip's `final` function during the
`BS_WRITE_TABLES` boot state.
## Build Process Integration
The `chip_operations` structures are integrated into the coreboot build
process through several mechanisms:
1. **Devicetree Processing**: The `sconfig` utility processes the
devicetree files and generates code that creates and links the device
structures.
2. **Static Structure Declaration**: Each chip (and often the mainboard)
defines its `chip_operations` structure in its respective `.c` file.
These structures are collected during the build process.
3. **External References**: The generated code in `build/static.c`
includes external references to these `chip_operations` structures.
4. **Linking**: The linker collects all the `chip_operations` structures
and includes them in the final firmware image.
This process ensures that the appropriate chip operations are available
during the boot process for each chip included in the devicetree.
## Best Practices for Implementing `chip_operations`
When implementing the `chip_operations` structure for a new chip,
follow these best practices:
1. **Provide a Meaningful Name**: The `name` field should be descriptive
and identify the chip clearly for debugging purposes.
2. **Implement `enable_dev` Correctly**: The `enable_dev` function should
assign the appropriate device operations based on device types and
functions. It should handle all device types that might be part of the chip.
Consider interactions with the mainboard `enable_dev`.
3. **Use Configuration Data**: The `init` and `final` functions should
make use of the chip configuration data passed via the `chip_info`
parameter (casting it to the correct type) to configure the chip
according to the settings specified in the devicetree.
4. **Minimize Dependencies**: The `init` function should minimize
dependencies on other chips being initialized, as the order of chip
initialization is not guaranteed.
5. **Handle Resources Properly**: If the chip manages resources (memory
regions, I/O ports, etc.), ensure that these are properly allocated and
assigned to devices, usually within the associated `device_operations`.
6. **Implement Error Handling**: Include appropriate error handling in
the initialization functions to handle hardware initialization failures
gracefully.
7. **Document Special Requirements**: If the chip has special
requirements or dependencies, document these clearly in comments or
accompanying documentation.
## Troubleshooting `chip_operations` Issues
When implementing or debugging `chip_operations`, you might encounter
certain issues:
1. **Missing Device Operations**: If devices are not being initialized
properly, check that the `enable_dev` function is correctly
assigning device operations based on device types. Ensure it's being
called during bus scanning.
2. **Initialization Order Problems**: If a chip's initialization depends
on another chip being initialized first, you might need to adjust the
initialization sequence or add explicit dependencies, possibly using
boot state callbacks if necessary.
3. **Configuration Data Issues**: If chip configuration settings are not
being applied correctly, check that the configuration structure is
correctly defined in `chip.h`, that the register values in the
devicetree match the expected format, and that the `chip_info` pointer
is cast correctly in the `init`/`final` functions.
4. **Build Errors**: If you encounter build errors related to
`chip_operations`, check that the structure is correctly defined and
that all required symbols are properly exported and linked. Check for
conflicts if multiple files define the same symbol.
5. **Runtime Failures**: If the chip initialization fails at runtime,
add debug logging (using `printk`) to the `init`, `enable_dev`, and
`final` functions to identify the specific point of failure.
## Advanced `chip_operations` Patterns
### Hierarchical Chip Initialization
For complex chips with multiple components, you can implement a
hierarchical initialization pattern within the `init` function:
```c
static void soc_init(void *chip_info)
{
/* Initialize common components first */
common_init(chip_info);
/* Initialize specific blocks */
pcie_init(chip_info);
usb_init(chip_info);
sata_init(chip_info);
/* Final SoC-wide configuration */
power_management_init(chip_info);
}
```
### Variant Support
For chips with multiple variants, you can implement variant detection
and specific initialization within the `init` function:
```c
static void soc_init(void *chip_info)
{
uint32_t variant = read_chip_variant();
/* Common initialization */
common_init(chip_info);
/* Variant-specific initialization */
switch (variant) {
case VARIANT_A:
variant_a_init(chip_info);
break;
case VARIANT_B:
variant_b_init(chip_info);
break;
default:
printk(BIOS_WARNING, "Unknown variant %u\\n", variant);
break;
}
}
```
### Conditional Feature Initialization
You can conditionally initialize features based on configuration settings
passed via `chip_info`:
```c
static void soc_init(void *chip_info)
{
struct soc_config *config = chip_info;
/* Always initialize core components */
core_init();
/* Conditionally initialize optional features */
if (config->enable_xhci)
xhci_init(config);
if (config->enable_sata)
sata_init(config);
if (config->enable_pcie)
pcie_init(config);
}
```
## Conclusion
The `chip_operations` structure is a fundamental component of coreboot's
chipset abstraction layer. It provides a standardized interface for chipset-
specific code to interact with coreboot's device initialization framework,
enabling support for a wide variety of chipsets while maintaining a
consistent initialization flow.
By implementing the `chip_operations` structure for a specific chipset
(and often for the mainboard), developers can integrate their
hardware-specific code with coreboot's device enumeration, configuration,
and initialization process. This structure serves as the bridge between
the declarative device descriptions in the devicetree and the imperative
code that initializes the hardware.
Understanding the `chip_operations` structure and its role in the
coreboot boot process is essential for anyone working on chipset or
mainboard support in coreboot. By following the best practices and
patterns outlined in this document, developers can create robust and
maintainable hardware support code that integrates seamlessly with the
coreboot firmware ecosystem.

View file

@ -1,696 +0,0 @@
# Device Operations in coreboot Firmware
## Introduction
The `device_operations` structure is a cornerstone of coreboot's
hardware abstraction layer. It represents a set of function pointers
defining how the firmware interacts with a specific hardware device
during various boot stages. This structure lets the coreboot
architecture establish a consistent interface for device initialization,
configuration, resource allocation, and ACPI table generation, while
allowing device-specific implementations behind this common interface.
At its core, `device_operations` applies the strategy pattern in
systems programming. It decouples algorithms (device operations) from
the core boot sequence, allowing devices to define their own behavior
while the boot process follows a predictable flow. This pattern enables
coreboot to support a wide range of hardware platforms with minimal
changes to the core boot sequence code.
## Structure Definition
The `device_operations` structure, defined in
`src/include/device/device.h`, consists of several function pointers,
each representing a specific operation performed on a device during
boot:
```c
struct device_operations {
void (*read_resources)(struct device *dev);
void (*set_resources)(struct device *dev);
void (*enable_resources)(struct device *dev);
void (*init)(struct device *dev);
void (*final)(struct device *dev);
void (*scan_bus)(struct device *bus);
void (*enable)(struct device *dev);
void (*vga_disable)(struct device *dev);
void (*reset_bus)(struct bus *bus);
int (*get_smbios_data)(struct device *dev, int *handle,
unsigned long *current);
void (*get_smbios_strings)(struct device *dev, struct smbios_type11 *t);
unsigned long (*write_acpi_tables)(const struct device *dev,
unsigned long start, struct acpi_rsdp *rsdp);
void (*acpi_fill_ssdt)(const struct device *dev);
const char *(*acpi_name)(const struct device *dev);
const char *(*acpi_hid)(const struct device *dev);
const struct pci_operations *ops_pci;
const struct i2c_bus_operations *ops_i2c_bus;
const struct spi_bus_operations *ops_spi_bus;
const struct smbus_bus_operations *ops_smbus_bus;
const struct pnp_mode_ops *ops_pnp_mode;
const struct gpio_operations *ops_gpio;
const struct mdio_bus_operations *ops_mdio;
};
```
### Core Resource Management Functions
* `read_resources`: Discovers and collects resources required by the
device (I/O ports, memory regions, IRQs, etc.). This typically
involves reading configuration registers or static device tree
information.
* `set_resources`: Assigns finalized resources to the device after the
resource allocation phase. This writes the assigned base addresses,
lengths, and other parameters back to the device structure, but not
necessarily to hardware registers yet.
* `enable_resources`: Activates the assigned resources in the device's
hardware registers (e.g., writing to PCI BARs, enabling memory
decoding).
### Device Lifecycle Functions
* `init`: Performs device-specific initialization, often requiring
access to the device's assigned resources. This is called after
resources have been enabled.
* `final`: Executes final setup or cleanup operations before the
payload is loaded. This is useful for tasks that depend on other
devices being initialized.
* `enable`: Enables the device in the hardware, often setting bits in
configuration registers to make the device active. Called after
`enable_resources`.
### Bus Management Functions
* `scan_bus`: Enumerates child devices on a bus device (e.g., scanning
a PCI bus for devices, probing I2C devices). Only applicable to
devices that act as buses.
* `reset_bus`: Resets all devices on a specific bus.
* `vga_disable`: Disables VGA decoding on a PCI device when another VGA
device is active. Used to manage legacy VGA resources.
### System Table Generation Functions
* `get_smbios_data`: Provides SMBIOS data specific to the device for
Type 9 (System Slots) or Type 41 (Onboard Devices Extended
Information).
* `get_smbios_strings`: Supplies string information for SMBIOS tables,
often related to the data provided by `get_smbios_data`.
* `write_acpi_tables`: Generates device-specific ACPI tables (like SSDTs)
or contributes data to system-wide tables.
* `acpi_fill_ssdt`: Adds device-specific objects (scopes, methods, data)
to the Secondary System Description Table (SSDT).
* `acpi_name`: Returns the ACPI name for the device (e.g.,
`\_SB.PCI0.GFX0`). This defines the device's path in the ACPI
namespace.
* `acpi_hid`: Returns the ACPI Hardware ID (HID) for the device (e.g.,
`PNP0A08`). Used by the OS to match drivers.
### Bus-Specific Operation Pointers
These fields point to bus-specific operation structures when a device
functions as a bus controller (or exposes bus-like functionality). See
the "Bus-Specific Operations" section for details.
* `ops_pci`: Operations for PCI configuration space access.
* `ops_i2c_bus`: Operations for I2C bus transactions (read, write,
transfer).
* `ops_spi_bus`: Operations for SPI bus transactions.
* `ops_smbus_bus`: Operations for SMBus transactions.
* `ops_pnp_mode`: Operations for Plug-and-Play device configuration.
* `ops_gpio`: Operations for GPIO control (get, set, configure
direction/pulls).
* `ops_mdio`: Operations for MDIO (Management Data Input/Output) bus
access, used for Ethernet PHYs.
## Device Lifecycle in coreboot
The function pointers in `device_operations` are called at specific
stages during the boot process, following a sequence defined in
coreboot's boot state machine (`src/lib/hardwaremain.c`). Understanding
this lifecycle helps developers implement appropriate behavior for each
function pointer.
### Boot Sequence and Device Operations
coreboot's main device initialization sequence involves these boot
states:
1. **BS_DEV_INIT_CHIPS** (`dev_initialize_chips()`): Initializes chip
drivers (`chip_operations`).
2. **BS_DEV_ENUMERATE** (`dev_enumerate()`): Discovers and enumerates
devices.
* Calls `scan_bus()` for each bus to detect child devices.
3. **BS_DEV_RESOURCES** (`dev_configure()`): Allocates resources across
all enumerated devices.
* Calls `read_resources()` for each device to discover required
resources.
* Calls `set_resources()` for each device to assign allocated
resources back to the `struct device`.
4. **BS_DEV_ENABLE** (`dev_enable()`): Enables devices and their
resources.
* Calls `enable_resources()` for each device to activate assigned
resources in hardware.
* Calls `enable()` for each device to perform general hardware
enablement.
5. **BS_DEV_INIT** (`dev_initialize()`): Initializes devices.
* Calls `init()` for each device to perform device-specific setup.
6. **BS_POST_DEVICE** (`dev_finalize()`): Finalizes devices before
payload loading.
* Calls `final()` for each device for any final cleanup or setup.
The sequence is primarily driven by the `boot_states` array in
`src/lib/hardwaremain.c`:
```c
static struct boot_state boot_states[] = {
/* ... other states ... */
BS_INIT_ENTRY(BS_PRE_DEVICE, bs_pre_device),
BS_INIT_ENTRY(BS_DEV_INIT_CHIPS, bs_dev_init_chips),
BS_INIT_ENTRY(BS_DEV_ENUMERATE, bs_dev_enumerate),
BS_INIT_ENTRY(BS_DEV_RESOURCES, bs_dev_resources),
BS_INIT_ENTRY(BS_DEV_ENABLE, bs_dev_enable),
BS_INIT_ENTRY(BS_DEV_INIT, bs_dev_init),
BS_INIT_ENTRY(BS_POST_DEVICE, bs_post_device),
/* ... other states ... */
};
```
Later stages include ACPI and SMBIOS table generation, where functions
like `write_acpi_tables()`, `acpi_fill_ssdt()`, `get_smbios_data()`, and
`get_smbios_strings()` are invoked as part of the table construction
process.
## Inheritance and Code Reuse Patterns
The `device_operations` structure enables several patterns for code
reuse:
### 1. Default Implementations
coreboot provides default implementations for common device types (like
root devices, PCI devices, PCI bridges), which can be used directly or
extended. Chip or mainboard code often assigns these defaults if no
specific driver is found.
```c
/* From src/device/root_device.c */
struct device_operations default_dev_ops_root = {
.read_resources = noop_read_resources,
.set_resources = noop_set_resources,
.scan_bus = scan_static_bus,
.reset_bus = root_dev_reset,
#if CONFIG(HAVE_ACPI_TABLES)
.acpi_name = root_dev_acpi_name,
#endif
};
```
### 2. No-op Functions
Simple shim functions (often static inline) are provided for cases where
a device doesn't need to implement specific operations. Using these avoids
leaving function pointers NULL.
```c
/* From src/include/device/device.h */
static inline void noop_read_resources(struct device *dev) {}
static inline void noop_set_resources(struct device *dev) {}
```
### 3. Chain of Responsibility / Delegation
Some implementations delegate to parent devices or use helper functions
when they can't handle an operation themselves or when common logic can
be shared. For example, ACPI name generation often traverses up the
device tree.
```c
/* Simplified example logic */
const char *acpi_device_name(const struct device *dev)
{
const char *name = NULL;
const struct device *pdev = dev;
/* Check for device specific handler */
if (dev->ops && dev->ops->acpi_name) {
name = dev->ops->acpi_name(dev);
if (name)
return name; /* Device handled it */
}
/* Walk up the tree to find if any parent can provide a name */
while (pdev->upstream && pdev->upstream->dev) {
pdev = pdev->upstream->dev;
if (pdev->ops && pdev->ops->acpi_name) {
/* Note: Parent's acpi_name might handle the original child 'dev' */
name = pdev->ops->acpi_name(dev);
if (name)
return name; /* Parent handled it */
}
}
/* Fallback or default logic if needed */
return NULL;
}
```
This pattern allows parent devices (like buses) to provide default
behavior or naming schemes if a child device doesn't specify its own.
## Implementation Examples
These examples show typical `device_operations` assignments. Actual
implementations might involve more conditional compilation based on
Kconfig options.
### PCI Device Operations (Default)
```c
/* From src/device/pci_device.c */
struct device_operations default_pci_ops_dev = {
.read_resources = pci_dev_read_resources,
.set_resources = pci_dev_set_resources,
.enable_resources = pci_dev_enable_resources,
#if CONFIG(HAVE_ACPI_TABLES)
.write_acpi_tables = pci_rom_write_acpi_tables,
.acpi_fill_ssdt = pci_rom_ssdt,
#endif
.init = pci_dev_init,
/* Assigns PCI-specific operations */
.ops_pci = &pci_dev_ops_pci,
};
```
### CPU Cluster Operations
```c
/* From src/soc/intel/alderlake/chip.c (representative example) */
static struct device_operations cpu_bus_ops = {
.read_resources = noop_read_resources,
.set_resources = noop_set_resources,
.enable_resources = cpu_set_north_irqs,
#if CONFIG(HAVE_ACPI_TABLES)
.acpi_fill_ssdt = cpu_fill_ssdt,
#endif
/* CPU clusters often don't need scan_bus, init, etc. */
};
```
### GPIO Controller Operations
```c
/* From src/soc/intel/common/block/gpio/gpio_dev.c */
static struct gpio_operations gpio_ops = {
.get = gpio_get,
.set = gpio_set,
/* ... other GPIO functions ... */
};
struct device_operations block_gpio_ops = {
.read_resources = noop_read_resources,
.set_resources = noop_set_resources,
/* Assigns GPIO-specific operations */
.ops_gpio = &gpio_ops,
};
```
## Registration and Discovery
How are `device_operations` structures associated with `struct device`
instances?
### 1. Static Assignment (via `chip_operations`)
For devices known at build time (defined in devicetree.cb), the
`device_operations` structure is often assigned in the SOC's or
mainboard's `chip_operations->enable_dev()` function based on the
device path type or other properties.
```c
/* Example from src/soc/intel/alderlake/chip.c */
static void soc_enable(struct device *dev)
{
/* Assign ops based on the device's role in the tree */
if (dev->path.type == DEVICE_PATH_DOMAIN)
dev->ops = &pci_domain_ops; /* Handles PCI domain resources */
else if (dev->path.type == DEVICE_PATH_CPU_CLUSTER)
dev->ops = &cpu_bus_ops; /* Handles CPU cluster setup */
else if (dev->path.type == DEVICE_PATH_GPIO)
block_gpio_enable(dev); /* Assigns block_gpio_ops */
/* ... other assignments for specific PCI devices, etc. ... */
}
```
The `enable_dev` function is part of `struct chip_operations`, which
handles broader chip-level initialization (see "Relationship with
`chip_operations`" section).
### 2. Dynamic Detection (PCI Drivers)
For PCI devices discovered during bus scanning (`scan_bus`), coreboot
looks through a list of registered PCI drivers (`_pci_drivers` array)
to find one matching the device's vendor and device IDs.
```c
/* Logic from src/device/pci_device.c::set_pci_ops() */
static void set_pci_ops(struct device *dev)
{
struct pci_driver *driver;
/* Check if ops already assigned (e.g., by chip_ops->enable_dev) */
if (dev->ops)
return;
/* Look through registered PCI drivers */
for (driver = &_pci_drivers[0]; driver != &_epci_drivers[0]; driver++) {
if ((driver->vendor == dev->vendor) &&
device_id_match(driver, dev->device)) {
/* Found a matching driver, assign its ops */
dev->ops = (struct device_operations *)driver->ops;
printk(BIOS_SPEW, "%s: Assigned ops from driver for %04x:%04x\n",
dev_path(dev), driver->vendor, driver->device);
return; /* Stop searching */
}
}
/* Fall back to default operations if no specific driver found */
if (!dev->ops) {
if ((dev->hdr_type & 0x7f) == PCI_HEADER_TYPE_BRIDGE) {
dev->ops = get_pci_bridge_ops(dev); /* Special ops for bridges */
} else {
dev->ops = &default_pci_ops_dev; /* Default for normal devices */
}
printk(BIOS_SPEW, "%s: Assigned default PCI ops\n", dev_path(dev));
}
}
```
## Build Process Integration
The `device_operations` structures are integrated into the coreboot
build process:
1. **Static Device Tree**: The mainboard's `devicetree.cb` defines the
initial device hierarchy. The build process converts this into C
code (`static.c`) containing `struct device` instances.
2. **PCI Driver Registration**: PCI drivers (containing their own
`device_operations`) register themselves using the `__pci_driver`
linker set macro.
```c
/* Example pattern */
struct pci_driver example_pci_driver __pci_driver = {
.ops = &example_device_ops, /* Pointer to device_operations */
.vendor = VENDOR_ID,
.device = DEVICE_ID, /* Or .devices for a list */
};
```
3. **Linking**: The build system collects all structures placed in the
`__pci_driver` section and creates the `_pci_drivers` array used by
`set_pci_ops()`. It ensures all necessary code (default ops, driver
ops, core device functions) is linked into the final firmware image.
## Relationship with `chip_operations`
It's important to distinguish `device_operations` from
`chip_operations` (defined in `src/include/chip.h`).
* `chip_operations`: Defines operations related to the overall chipset
or mainboard logic. It includes functions called earlier in the boot
process, like `enable_dev`, `init`, and `final`.
* `chip_operations->enable_dev()` is crucial as it often performs
initial setup for static devices and is the primary place where
`device_operations` pointers are *assigned* for non-PCI devices
based on their path or type.
* `chip_operations->init()` runs during `BS_DEV_INIT_CHIPS`, before
most `device_operations` functions.
* `device_operations`: Defines operations for *individual* devices
within the device tree. These are called *after* the corresponding
`chip_operations` stage and operate on a specific `struct device`.
Essentially, `chip_operations` sets the stage at the SoC/mainboard level,
including assigning the correct `device_operations` to static devices,
while `device_operations` handles the specific actions for each device
later in the boot process.
## Bus-Specific Operations
The `ops_*` pointers within `struct device_operations` (e.g., `ops_pci`,
`ops_i2c_bus`, `ops_spi_bus`, `ops_gpio`) provide a way for devices that
act as bus controllers or expose bus-like interfaces to offer
standardized access methods.
* **Purpose:** They abstract the low-level details of interacting with
that specific bus type. For example, a PCI host bridge device will
implement `struct pci_operations` via its `ops_pci` pointer,
allowing other code to perform PCI config reads/writes through it
without knowing the exact hardware mechanism. Similarly, an I2C
controller device implements `struct i2c_bus_operations` via
`ops_i2c_bus` to provide standard `read`, `write`, and `transfer`
functions for that bus segment.
* **Usage:** Code needing to interact with a bus first finds the
controller `struct device` in the tree, then accesses the relevant
bus operations through the appropriate `ops_*` pointer, passing the
target address or parameters. For instance, to talk to an I2C device
at address `0x50` on the bus controlled by `i2c_controller_dev`, one
might call:
`i2c_controller_dev->ops->ops_i2c_bus->transfer(...)`. Helper
functions often wrap this access pattern.
* **Implementation:** The structures like `struct pci_operations`,
`struct i2c_bus_operations`, etc., are defined in corresponding
header files (e.g., `src/include/device/pci_ops.h`,
`src/include/drivers/i2c/i2c_bus.h`). Devices acting as controllers
provide concrete implementations of these functions, tailored to their
hardware.
This mechanism allows coreboot to manage diverse bus types using a
consistent device model, where the controller device itself exposes the
necessary functions for interacting with devices on its bus.
## Best Practices
When implementing `device_operations`:
1. **Leverage Defaults/No-ops**: Use default or no-op implementations
whenever possible. Only override functions that require custom
behavior for your specific device.
2. **Error Handling**: Check return values from functions called within
your ops implementations and handle errors gracefully (e.g., log an
error, return an error code if applicable).
3. **Resource Management**: In `read_resources`, accurately declare all
resources (MMIO, I/O ports, IRQs) your device needs, specifying
flags like fixed vs. alignment, or bridge vs. standard device.
Incorrect resource declaration is a common source of issues.
4. **Initialization Order**: Be mindful of dependencies in `init`. If
your device relies on another device being fully initialized, consider
deferring that part of the initialization to the `final` callback,
which runs later.
5. **Minimal Implementation**: Only implement the functions relevant to
your device type. A simple MMIO device might only need
`read_resources`, `set_resources`, `enable_resources`, and perhaps
ACPI functions. A bus device additionally needs `scan_bus`.
6. **Bus Operations**: If implementing a bus controller, correctly
implement the corresponding bus operations structure (e.g.,
`struct pci_operations`, `struct i2c_bus_operations`) and assign it
to the appropriate `ops_*` field.
7. **ACPI/SMBIOS**: If the device needs OS visibility via ACPI or
SMBIOS, implement the relevant functions (`acpi_name`, `acpi_hid`,
`acpi_fill_ssdt`, `get_smbios_data`, etc.). Ensure ACPI names and
HIDs are correct according to specifications and platform needs.
## Logging and Debugging
Use coreboot's logging facilities (`printk`) within your `device_operations`
functions to provide visibility during development and debugging. Use
appropriate log levels (e.g., `BIOS_DEBUG`, `BIOS_INFO`, `BIOS_ERR`).
```c
static void example_device_init(struct device *dev)
{
printk(BIOS_DEBUG, "%s: Initializing device at %s\n", __func__,
dev_path(dev));
/* ... Device initialization code ... */
if (/* some condition */) {
printk(BIOS_SPEW, "%s: Condition met, applying setting X\n",
dev_path(dev));
/* ... */
}
if (/* error condition */) {
printk(BIOS_ERR, "%s: Failed to initialize feature Y!\n",
dev_path(dev));
/* Handle error */
}
printk(BIOS_DEBUG, "%s: Initialization complete for %s\n", __func__,
dev_path(dev));
}
```
Consistent logging helps trace the boot process and pinpoint where issues
occur.
## Common Troubleshooting
* **Missing Resource Declarations**:
* *Problem*: Device fails to function, or conflicts arise because a
required resource (MMIO range, I/O port, IRQ) was not declared
in `read_resources`. The resource allocator is unaware of the
need.
* *Solution*: Verify that `read_resources` correctly calls functions
like `pci_dev_read_resources` or manually adds all necessary
resources using functions like `mmio_resource()`,
`io_resource()`, etc. Check PCI BARs or device datasheets.
* **Initialization Order Issues**:
* *Problem*: `init()` fails because it depends on another device
that hasn't been fully initialized yet (e.g., accessing a shared
resource like SMBus before the SMBus controller is ready).
* *Solution*: Move the dependent initialization code to the `final`
callback if possible. Alternatively, ensure the dependency is met
by careful ordering in the device tree or using boot state
callbacks if necessary for complex scenarios.
* **Resource Conflicts**:
* *Problem*: Boot fails during resource allocation, or devices
misbehave because multiple devices requested the same
non-sharable resource (e.g., conflicting fixed MMIO regions).
* *Solution*: Review resource declarations in `read_resources` across
all relevant devices. Ensure fixed resources don't overlap. Check
if bridge windows are correctly defined and large enough. Use
coreboot's resource reporting logs to identify overlaps.
* **ACPI Table Generation Errors**:
* *Problem*: The operating system fails to recognize the device,
assigns the wrong driver, or the device doesn't function correctly
(e.g., power management issues).
* *Solution*: Double-check the `acpi_name`, `acpi_hid`, `_CRS`
(generated from assigned resources), and `acpi_fill_ssdt`
implementations. Verify names match the ACPI hierarchy and HIDs
match expected driver bindings. Ensure SSDT methods correctly
access hardware. Use OS debugging tools (e.g., `acpidump`, Device
Manager errors) to diagnose.
* **Incorrect `ops` Pointer Assigned**:
* *Problem*: Device behaves incorrectly because the wrong
`device_operations` structure was assigned (e.g., default PCI ops
assigned to a device needing a specific driver's ops).
* *Solution*: Check the logic in `chip_operations->enable_dev` (for
static devices) or the PCI driver registration (`__pci_driver`
macro and `set_pci_ops` fallback logic) to ensure the correct
`ops` structure is being selected and assigned based on device
type, path, or PCI ID. Add debug prints to verify which `ops`
structure is assigned.
## Advanced Usage
### Complex Device Hierarchies
For devices with non-standard interactions or complex initialization,
custom `device_operations` can be created, often inheriting from defaults
but overriding specific functions.
```c
static void advanced_device_init(struct device *dev)
{
/* First, perform standard PCI init */
pci_dev_init(dev);
/* Then, add custom initialization steps */
printk(BIOS_DEBUG, "%s: Performing advanced init\n", dev_path(dev));
/* ... custom register writes, configuration ... */
}
static const char *advanced_device_acpi_name(const struct device *dev)
{
/* Provide a custom ACPI name based on some property */
if (/* condition */)
return "ADV0001";
else
return "ADV0002";
}
/* Combine default and custom operations */
static struct device_operations advanced_device_ops = {
/* Inherit resource handling from default PCI ops */
.read_resources = pci_dev_read_resources,
.set_resources = pci_dev_set_resources,
.enable_resources = pci_dev_enable_resources,
/* Override init */
.init = advanced_device_init,
/* Override ACPI naming */
.acpi_name = advanced_device_acpi_name,
/* Other functions might use defaults or no-ops */
};
```
### Dynamic Configuration based on Probing
Some `init` or other op implementations might probe the device's
capabilities or read configuration data (e.g., from SPD, VPD, or straps)
and alter their behavior accordingly.
```c
static void conditional_device_init(struct device *dev)
{
uint8_t feature_flags;
/* Read capability register from the device */
feature_flags = pci_read_config8(dev, EXAMPLE_CAP_REG);
printk(BIOS_DEBUG, "%s: Feature flags: 0x%02x\n", dev_path(dev),
feature_flags);
/* Conditional initialization based on detected features */
if (feature_flags & FEATURE_X_ENABLED) {
printk(BIOS_INFO, "%s: Initializing Feature X\n", dev_path(dev));
init_feature_x(dev);
}
if (feature_flags & FEATURE_Y_ENABLED) {
printk(BIOS_INFO, "%s: Initializing Feature Y\n", dev_path(dev));
init_feature_y(dev);
}
}
```
## Conclusion
The `device_operations` structure is a powerful abstraction mechanism in
coreboot. It enables consistent handling of diverse hardware while
allowing for device-specific behavior. By providing a standard interface
for device operations throughout the boot process, it simplifies the
codebase, enhances maintainability, and provides the extensibility needed
to support new hardware platforms.
Understanding this structure, its relationship with `chip_operations`,
and its role in the boot process is essential for coreboot developers,
particularly when adding support for new devices or debugging hardware
initialization issues. By following the patterns and best practices
outlined here, developers can create robust and reusable device driver
implementations that integrate smoothly into the coreboot architecture.

View file

@ -1,684 +0,0 @@
# Devicetree
## Introduction to the coreboot devicetree
The first thing that may come to mind when one hears "DeviceTree" is a
different sort of description file that is generally passed to the Linux
kernel to describe a system's components. Both that devicetree and
coreboot's devicetree serve fundamentally the same purpose, but are
otherwise unrelated and have completely different syntax. The term
devicetree was used long before either version was created, and was
initially used in coreboot as a generic term.
coreboot's devicetree's main use is to define and describe the runtime
configuration and settings of the hardware on a board, chip or device
level. It defines which of the functions of the chips on the board are
enabled, and how they're configured.
The devicetree file is parsed during the build process by a utility
named `sconfig`, which translates the devicetree into a tree of C
structures containing the included devices. This code is placed in the
file `static.c` and a couple of header files, all under the `build`
directory. This file is then built into the binaries for the various
coreboot stages and is referred to during the coreboot boot process.
For the early stages of the coreboot boot process, the data that is
generated by `sconfig` is a useful resource, but this structure is the
critical architectural glue of ramstage. This structure gets filled in
with pointers to every chip's initialization code, allowing ramstage to
find and initialize those devices through the `chip_operations`
structures.
### History of coreboot's devicetree
The initial devicetree in coreboot was introduced in 2003 by Ron Minnich
as a part of the linuxbios config file, 'config.lb'. At this point both
the devicetree and config options were in the same file. In 2009,
when Kconfig was added into the coreboot build, devicetree was split
out into its own file for each mainboard in a commit with this message:
```text
devicetree.cb
The devicetree that formerly resided in src/mainboard/*/*/Config.lb.
Just without the build system crap
```
The devicetree structure was initially mainly used only in ramstage for
PCI device enumeration, configuration and resource allocation. It has
since expanded for use in the pre-ram stages as a read-only structure.
The language used in the devicetree has been expanded greatly since it
was first introduced as well, adding new features every year or so.
### Devicetree Registers
In coreboot, the devicetree register setting is one of the two main
methods used to configure a board's properties. In this way, devicetree
is similar in function to Kconfig. It's more flexible in many ways as
it can specify not only single values, but also arrays or structures.
It's also even more static than Kconfig because there's no update
mechanism for it other than editing the devicetree files.
Chip-specific configuration values are often set using `register`
definitions within a `chip` block, corresponding to a `struct` defined
in the chip's `chip.h` file.
For example, in a `chip drivers/gpio/acpi` block, you might set a GPE:
```text
register "gpe0_sts" = "0x42"
```
### Adding new static configuration options: Devicetree or Kconfig
When adding options for a new board or chip, there is frequently a
decision that needs to be made about how the option should be added.
Using the devicetree or Kconfig are the two typical methods of
build-time configuration. Below are some general guidelines on when to
use each.
Kconfig should be used if the option configures the build in a Makefile,
or if the option is something that should be user selectable. Kconfig
is also preferred if the configuration is a global option and not limited
to a single chip. Another thing Kconfig excels at is handling decisions
based on other configuration options, which devicetree cannot do.
Devicetree should obviously be used to define the hardware hierarchy.
It's also preferred if the option is only used in C code and is static
for a mainboard, or if the option is chip-specific. As mentioned
earlier, devicetree registers can also define structures or arrays,
which Kconfig cannot.
Both Kconfig and devicetree can be used in C code for runtime
configuration, but there's a significant difference in how they are
handled. Because Kconfig generates a `#define` for the choice, the
compiler can eliminate code paths not used by the option. Devicetree
options, however, are actual runtime selections, and the code for all
choices remains in the final build.
## Basic Devicetree Syntax
The coreboot devicetree uses a custom language parsed by the `sconfig`
utility. Here's a brief overview of the main keywords and concepts:
* **`chip <directory>`**: Defines a collection of devices associated
with the code in the specified directory. `sconfig` may also parse a
`chip.h` file within this directory for register definitions.
* **`device <type> <id> [on|off] [alias <name>] ... end`**: Defines a
specific hardware device.
* `<type>`: Specifies the device type (e.g., `pci`, `cpu_cluster`,
`i2c`).
* `<id>`: A unique identifier for the device within its type/bus
(e.g., PCI BDF `17.0`, I2C address `0x50`).
* `on`/`off`: Enables or disables the device definition.
* `alias <name>`: Assigns a human-readable alias for referencing
this device elsewhere (often used in `chipset.cb`).
* `end`: Marks the end of the device definition block. Registers
and other properties are defined between `device` and `end`.
* **`register "<name>" = <value>`**: Sets the value of a configuration
register defined in the corresponding `chip.h` structure. The value
can be a number, string, or complex structure initialization.
* **`probe <field> <option>`**: Used for firmware configuration
(`fw_config`), indicating a setting should be probed at runtime.
* **`ops "<identifier>"`**: Associates a `chip_operations` structure
with the device, used primarily in ramstage for device initialization.
* **`fw_config field <name> size <bits> ... end`**: Defines a firmware
configuration field, often used for passing board-specific data to
payloads. Options within the field are defined using `option`.
* **`ref <alias>`**: Used within `device` definitions in `devicetree.cb`
or `overridetree.cb` to refer to a device defined (usually via an
`alias`) in a lower-level file like `chipset.cb`.
* **`# <comment text>`**: Single-line comments.
Device definitions can be nested within `chip` blocks. `end` keywords
close the current block (`device` or `chip`).
## Three levels of devicetree files
There are currently three different levels of devicetrees used to build
up the structure of components and register values in coreboot. From
the lowest, most general level to the highest and most specific, they
are `chipset.cb`, `devicetree.cb`, and `overridetree.cb`.
Unless there's a specific reason to name them something other than these
names, they should be used.
For newer SoCs and chipsets, there will generally be a `chipset.cb` file.
Every mainboard requires a `devicetree.cb` file, although it can be empty
if everything is inherited from the `chipset.cb`. An `overridetree.cb`
file is only required if variants have differences from the primary
mainboard's `devicetree.cb`.
### SoC / chipset level, `chipset.cb`
The `chipset.cb` file was added in October 2020, allowing a single
chipset or SoC to provide a "base level" devicetree, reducing
duplication between mainboards.
The `chipset.cb` file also typically defines human-readable "aliases"
for particular devices so that mainboards can use those instead of PCI
device/function numbers or other hardware identifiers.
The use of the `chipset.cb` file is specified in Kconfig by the
`CHIPSET_DEVICETREE` symbol, which provides the path to the file.
In a `chipset.cb` file, you might see lines like this:
```text
# Chip definition for the SoC/chipset itself
chip soc/intel/common/block
# Define PCI device 17.0, alias it to "sata", and default it off
device pci 17.0 alias sata off end
# Define PCI device 1e.0, alias it to "uart0", and default it off
device pci 1e.0 alias uart0 off end
end # chip soc/intel/common/block
```
This defines the devices, assigns aliases, and sets their default state.
### Primary mainboard level, `devicetree.cb`
Each mainboard must have a `devicetree.cb` file. The filename and path are
typically set by the `DEVICETREE` Kconfig symbol, defaulting to
`src/mainboard/<VENDOR>/<BOARD>/devicetree.cb`.
If a mainboard using the above `chipset.cb` wanted both devices enabled,
its `devicetree.cb` might contain:
```text
# Reference the SATA device by its alias and enable it
device ref sata on end
# Reference the UART0 device by its alias and enable it
device ref uart0 on end
```
The `ref` keyword looks up the device (usually by alias) defined in a
lower-level file (`chipset.cb` in this case) and modifies its properties.
### Mainboard variant level, `overridetree.cb`
Introduced in 2018 to reduce duplication and maintenance for board
variants, the `overridetree.cb` file is the most specific level.
This allows a base `devicetree.cb` at the top mainboard level shared by
all variants. Each variant then only needs an `overridetree.cb` to
specify its differences.
The override tree filename is set in Kconfig with the
`OVERRIDE_DEVICETREE` symbol and is typically named `overridetree.cb`.
Finally, if one variant of the mainboard lacked a SATA connector, it
could disable the SATA device again using the following in its specific
`overridetree.cb`:
```text
# Reference the SATA device by alias and disable it for this variant
device ref sata off end
```
## Additional files
### `chip.h` files
coreboot looks at a "chip" as a collection of devices. This collection
can be a single logical device or multiple different ones. The `chip`
keyword starts this collection. Following the `chip` keyword is a
directory path (relative to `src/`) containing the code for that chip
or logical block of hardware.
There may optionally be a `chip.h` file in that directory. If present,
`sconfig` parses this file to define a C structure containing the
"register definitions" for the chip. The values for this structure's
members are set using the `register` keyword in one of the devicetree
files (`chipset.cb`, `devicetree.cb`, `overridetree.cb`). If not
explicitly set, members typically default to 0 or follow standard C
initialization rules. The `chip.h` file frequently also contains C
macros, enums, and sub-structures used for setting the members of the
main register structure.
The C structure for the chip's register definition is named after the
directory containing the `chip.h` file, with slashes (`/`) changed to
underscores (`_`), and `_config` appended. The leading `src/` is omitted.
This means that a line in a devicetree file like:
`chip drivers/i2c/hid`
would cause `sconfig` to look for `src/drivers/i2c/hid/chip.h`. If found,
the register definition structure it contains would be named
`drivers_i2c_hid_config`.
Here is the content of `src/drivers/i2c/hid/chip.h`:
```c
/* SPDX-License-Identifier: GPL-2.0-only */
#ifndef __DRIVERS_I2C_HID_CHIP_H__
#define __DRIVERS_I2C_HID_CHIP_H__
#include <drivers/i2c/generic/chip.h>
#define I2C_HID_CID "PNP0C50"
struct drivers_i2c_hid_config {
struct drivers_i2c_generic_config generic;
uint8_t hid_desc_reg_offset;
};
#endif /* __I2C_HID_CHIP_H__ */
```
In a devicetree, you could set `hid_desc_reg_offset` like this:
```text
chip drivers/i2c/hid
device i2c 0x2c on
# Set the HID descriptor register offset
register "hid_desc_reg_offset" = "0x01"
end
end
```
## The `sconfig` utility and generated files
### `util/sconfig`
`sconfig` is the tool that parses the coreboot devicetrees and turns
them into a collection of C structures. This is a coreboot-specific
tool, built using flex & bison to define and parse the domain-specific
language used by coreboot's devicetree.
`sconfig` is called by the makefiles during the build process and doesn't
generally need to be run directly. If run manually (e.g.,
`build/util/sconfig/sconfig --help`), it shows its command-line options.
The exact options might vary slightly, but typically include:
```text
usage: sconfig <options>
-c | --output_c : Path to output static.c file (required)
-r | --output_h : Path to header static.h file (required)
-d | --output_d : Path to header static_devices.h file (required)
-f | --output_f : Path to header static_fw_config.h file (required)
-m | --mainboard_devtree : Path to mainboard devicetree file (required)
-o | --override_devtree : Path to override devicetree file (optional)
-p | --chipset_devtree : Path to chipset/SOC devicetree file (optional)
```
### `sconfig` inputs
The `sconfig` input files `chip.h`, `chipset.cb`, `devicetree.cb`, and
`overridetree.cb` were discussed previously. As the usage above shows,
the only required input file is the mainboard devicetree (`-m`). The
additional devicetree files, `chipset.cb` (`-p`) and `overridetree.cb`
(`-o`), are optional. The `chip.h` files do not need to be specified on
the command line; their locations are determined by the `chip` directory
paths within the `.cb` files.
Constructing the devicetree input files will be discussed later.
### `sconfig` outputs
#### `static.c`
This is the primary C file generated by `sconfig`. It contains the static
definitions of the device tree structures, including device nodes, bus
links, and register configuration data.
For historic reasons, `static.c` is generated in the
`build/mainboard/<VENDOR>/<BOARD>` directory.
#### `static.h`
The `static.h` file is the main header file included by most coreboot C
files that need access to the devicetree data. It is included by
`src/include/device/device.h`, which provides the primary API
(definitions, structures, function prototypes) for interacting with the
devicetree-generated output.
`static.h` used to contain all generated declarations directly. As of
October 2020, it simply includes the other two generated header files
(`static_devices.h` and `static_fw_config.h`). This separation allows
the firmware config options (`fw_config`) to be used independently, for
example, by a payload.
#### `static_devices.h`
The file `static_devices.h` contains `extern` declarations for all the
device structures (`struct device`) defined in `static.c`. This allows
other C files to reference the generated device tree nodes.
#### `static_fw_config.h`
`static_fw_config.h` contains only the `FW_CONFIG_FIELD_*` macro results,
derived from `fw_config` entries in the devicetree. This makes it easily
consumable by payloads or other components needing platform `FW_CONFIG`
data without pulling in the full device tree structure.
## Devicetree Example
### A very simple devicetree
This is the `devicetree.cb` file from
`src/mainboard/sifive/hifive-unleashed`, with line numbers added for
reference. Non-x86 devicetree files are often simpler than their x86
counterparts.
```text
1 # SPDX-License-Identifier: GPL-2.0-only
2 chip soc/sifive/fu540
3 device cpu_cluster 0 on end
4 end
```
This can be broken down as follows:
Line 1: Comments start with `#`. This line is the SPDX license
identifier for the file.
Line 2: `chip soc/sifive/fu540` starts a block for the SiFive FU540 SoC.
`sconfig` will look for code and potentially a `chip.h` in
`src/soc/sifive/fu540/`.
Line 3: `device cpu_cluster 0 on end` defines a device of type
`cpu_cluster` with ID `0`. It's marked as enabled (`on`). Since there are
no registers or other properties defined between `device` and `end`, this
is a simple enablement entry.
Line 4: `end` closes the block started by the `chip` keyword on line 2.
### Generated files
Continuing with the simple `sifive/hifive-unleashed` mainboard example,
these are the files generated by `sconfig` from the devicetree above (as
of mid-2022; exact output can change). Because the input devicetree is
minimal, the generated files are also quite sparse.
#### `build/static.h`
```c
#ifndef __STATIC_DEVICE_TREE_H
#define __STATIC_DEVICE_TREE_H
#include <static_fw_config.h>
#include <static_devices.h>
#endif /* __STATIC_DEVICE_TREE_H */
```
(Includes the other generated headers.)
#### `build/static_devices.h`
```c
#ifndef __STATIC_DEVICES_H
#define __STATIC_DEVICES_H
#include <device/device.h>
/* expose_device_names */
#endif /* __STATIC_DEVICE_NAMES_H */
```
(Includes `device/device.h` but contains no actual device externs beyond
the implicit root device, as the simple example didn't define complex
devices requiring separate structs.)
#### `build/static_fw_config.h`
```c
#ifndef __STATIC_FW_CONFIG_H
#define __STATIC_FW_CONFIG_H
#endif /* __STATIC_FW_CONFIG_H */
```
(Empty because the example `devicetree.cb` did not use `fw_config`.)
#### `build/mainboard/sifive/hifive-unleashed/static.c`
##### Includes
```text
1 #include <boot/coreboot_tables.h>
2 #include <device/device.h>
3 #include <device/pci.h>
4 #include <fw_config.h>
5 #include <static.h>
```
Lines 1-5: Includes header files required for the following structure
definitions and macros.
##### Declarations for chip-ops
```text
6
7 #if !DEVTREE_EARLY
8 __attribute__((weak)) struct chip_operations mainboard_ops = {};
9 extern struct chip_operations soc_sifive_fu540_ops;
10 #endif
```
Lines 7 & 10: The `ops` structures inside this `#if !DEVTREE_EARLY` block
are only relevant and linked in ramstage.
Lines 8-9: Declarations for `chip_operations` structures. This section
expands as more chips are added to the devicetree.
* Line 8: `mainboard_ops` is always present. It's defined as `weak`
because the mainboard C code may or may not provide this structure.
* Line 9: This `extern` is generated by the `chip soc/sifive/fu540`
declaration in the `devicetree.cb`. There will be a similar line for
every `chip` declared.
##### `STORAGE` definition
```text
11
12 #define STORAGE static __unused DEVTREE_CONST
```
Line 12: This macro conditionally adds `const` based on the build stage.
It resolves to `static __unused const` in early stages (pre-RAM) and
`static __unused` in ramstage, where the structures might be modified.
##### Structure definitions
```text
13
14
15 /* pass 0 */
16 STORAGE struct bus dev_root_links[];
17 STORAGE struct device _dev_0;
18 DEVTREE_CONST struct device * DEVTREE_CONST last_dev = &_dev_0;
```
Lines 16-18: Forward declarations of the static structures generated by
`sconfig` based on the devicetree input. `_dev_0` corresponds to the
`cpu_cluster 0` device.
##### Register Structures
```text
19
20 /* chip configs */
```
Line 20: This section is empty for this mainboard because the
`soc/sifive/fu540/chip.h` file (if it exists) does not define a register
structure, or the devicetree did not instantiate it using `register`.
Otherwise, this section would contain the static initialization of chip
configuration structures based on `register` entries.
##### `dev_root` structure
Lines 21-44: `dev_root`. This structure represents the root of the
coreboot device tree. It is always generated, regardless of the content
of the `devicetree.cb` file. It serves as the entry point for traversing
the tree.
```text
21
22 /* pass 1 */
23 DEVTREE_CONST struct device dev_root = {
24 #if !DEVTREE_EARLY
25 .ops = &default_dev_ops_root,
26 #endif
27 .bus = &dev_root_links[0],
28 .path = { .type = DEVICE_PATH_ROOT },
29 .enabled = 1,
30 .hidden = 0,
31 .mandatory = 0,
32 .on_mainboard = 1,
33 .link_list = &dev_root_links[0],
34 .sibling = NULL,
35 #if !DEVTREE_EARLY
36 .chip_ops = &mainboard_ops,
37 .name = mainboard_name,
38 #endif
39 .next=&_dev_0,
40 #if !DEVTREE_EARLY
41 #if CONFIG(GENERATE_SMBIOS_TABLES)
42 #endif
43 #endif
44 };
```
* Lines 24-26: Points to a default ramstage `device_operation`
structure (`default_dev_ops_root`) found in
`src/device/root_device.c`. This structure typically does little by
default but can be overridden or utilized by mainboard code via the
`chip_operations->enable_dev()` hook for tasks like ACPI table
generation.
* Line 27: `.bus`: Pointer to the bus structure associated with this
device. For the root device, this points to its own bus structure.
* Line 28: `.path`: The unique path identifier for this device. The type
is `DEVICE_PATH_ROOT`.
* Lines 29-32: Device status flags.
* `enabled`: Set based on `on`/`off` in the devicetree (always on
for `dev_root`). Can be modified later (e.g., during enumeration
in ramstage).
* `hidden`, `mandatory`: Set only by corresponding keywords in the
devicetree (not used here).
* `on_mainboard`: Indicates the device was defined in the static
devicetree, as opposed to being discovered dynamically (e.g., via
PCI enumeration). Always true for `dev_root`.
* Line 33: `.link_list`: Pointer to the list of child buses attached to
this device.
* Line 34: `.sibling`: Pointer to the next device at the same level in
the tree. Should always be `NULL` for `dev_root`.
* Line 36: `.chip_ops`: Pointer to the mainboard's `chip_operations`
structure (the `weak` `mainboard_ops`). Although not a physical
chip, the mainboard gets this to hook into the boot process like
other chips.
* Line 37: `.name`: A string identifier, typically the mainboard name,
set at build time (from `src/device/root_device.c`).
* Line 39: `.next`: Pointer used internally by `sconfig` during tree
construction. Points to the next device structure processed (`_dev_0`).
##### `dev_root_links`
Lines 45-52: The `dev_root` bus structure array.
This array (`struct bus`) holds pointers defining the bus topology. Each
element represents a link on a bus. `dev_root` acts as the bridge for the
top-level bus.
A new bus structure array is typically created for each distinct bus type
or domain originating from a bridge device in the devicetree (e.g., PCI
domain 0, LPC bus).
```text
45 STORAGE struct bus dev_root_links[] = {
46 [0] = {
47 .link_num = 0,
48 .dev = &dev_root,
49 .children = &_dev_0,
50 .next = NULL,
51 },
52 };
```
* Line 47: `.link_num`: Index of this link within the bus array.
* Line 48: `.dev`: Pointer back to the bridge device structure for this
bus (`dev_root`).
* Line 49: `.children`: Pointer to the first child device structure on
this bus (`_dev_0`).
* Line 50: `.next`: Pointer to the next bridge device on the *parent*
bus. Since `dev_root` has no parent bus, this is `NULL`.
##### `_dev_0`
Lines 53-72: The `cpu_cluster` device structure (`_dev_0`).
This structure corresponds directly to the
`device cpu_cluster 0 on end` line in the `devicetree.cb`.
```text
53 STORAGE struct device _dev_0 = {
54 #if !DEVTREE_EARLY
55 .ops = NULL,
56 #endif
57 .bus = &dev_root_links[0],
58 .path = {.type=DEVICE_PATH_CPU_CLUSTER,{.cpu_cluster={ .cluster = 0x0 }}},
59 .enabled = 1,
60 .hidden = 0,
61 .mandatory = 0,
62 .on_mainboard = 1,
63 .link_list = NULL,
64 .sibling = NULL,
65 #if !DEVTREE_EARLY
66 .chip_ops = &soc_sifive_fu540_ops,
67 #endif
68 #if !DEVTREE_EARLY
69 #if CONFIG(GENERATE_SMBIOS_TABLES)
70 #endif
71 #endif
72 };
```
* Lines 54-56: `.ops`: Pointer to a `device_operations` structure. This
is `NULL` because this entry represents the `chip` itself, not a
specific functional sub-device requiring device-level operations. The
chip-level operations are handled by `chip_ops`.
* Line 57: `.bus`: Pointer to the bus structure this device resides on.
Since it's directly under `dev_root`, it points to `dev_root_links[0]`.
* Line 58: `.path`: The unique device path structure (defined in
`src/include/device/path.h`). Type is `DEVICE_PATH_CPU_CLUSTER`,
and the cluster ID is `0`, matching the devicetree entry. This path
is used when searching the tree (e.g., with `dev_find_path()`).
* Lines 59-62: Enumeration Status. Similar to `dev_root`. `enabled = 1`
comes from the `on` keyword.
* Line 63: `.link_list`: Pointer to child buses. `NULL` because this
`cpu_cluster` device doesn't bridge to any further buses in this
simple example.
* Line 64: `.sibling`: Pointer to the next device at the same level
(i.e., another device directly under `dev_root`). `NULL` as it's the
only child.
* Lines 65-67: `.chip_ops`: Pointer to the processor's `chip_operations`
structure (`soc_sifive_fu540_ops`), used in ramstage for SoC/CPU
initialization steps. This link comes from the `chip soc/sifive/fu540`
declaration.
* Lines 68-71: Placeholder for SMBIOS information, enabled by Kconfig.
Not used in this example.

File diff suppressed because it is too large Load diff

View file

@ -1,15 +0,0 @@
# coreboot internals
This section contains documentation about the configuration and
programming APIs internal to coreboot
## Configuration
```{toctree}
:maxdepth: 1
coreboot devicetree <devicetree.md>
coreboot devicetree language <devicetree_language.md>
Chip Operations <chip_operations.md>
Device Operations <device_operations>
```

View file

@ -2,284 +2,225 @@
## Motivation
The firmware configuration interface in coreboot is designed to support
a wide variety of configuration options in that are dictated by the
hardware at runtime. This allows a single BIOS image to be used across a
wide variety of devices which may have key differences but are otherwise
similar enough to use the same coreboot build target.
The firmware configuration interface in coreboot is designed to support a wide variety of
configuration options in that are dictated by the hardware at runtime. This allows a single
BIOS image to be used across a wide variety of devices which may have key differences but are
otherwise similar enough to use the same coreboot build target.
The initial implementation is designed to take advantage of a bitmask
returned by the Embedded Controller on Google ChromeOS devices which
allows the manufacturer to use the same firmware image across multiple
devices by selecting various options at runtime. See the ChromiumOS
The initial implementation is designed to take advantage of a bitmask returned by the Embedded
Controller on Google ChromeOS devices which allows the manufacturer to use the same firmware
image across multiple devices by selecting various options at runtime. See the ChromiumOS
[Firmware Config][1] documentation for more information.
This firmware configuration interface differs from the CMOS option
interface in that this bitmask value is not intended as a
user-configurable setting as the configuration values must match the
actual hardware. In the case where a user was to swap their hardware
this value would need to be updated or overridden.
This firmware configuration interface differs from the CMOS option interface in that this
bitmask value is not intended as a user-configurable setting as the configuration values must
match the actual hardware. In the case where a user was to swap their hardware this value
would need to be updated or overridden.
## Device Presence
One common example of why a firmware configuration interface is
important is determining if a device is present in the system. With some
bus topologies and hardware mechanisms it is possible to probe and
enumerate this at runtime:
One common example of why a firmware configuration interface is important is determining if a
device is present in the system. With some bus topologies and hardware mechanisms it is
possible to probe and enumerate this at runtime:
- PCI is a self-discoverable bus and is very easy to handle.
- I2C devices can often be probed with a combination of bus and address.
- The use of GPIOs with external strap to ground or different voltages
can be used to detect presence of a device.
- The use of GPIOs with external strap to ground or different voltages can be used to detect
presence of a device.
However there are several cases where this is insufficient:
- I2C peripherals that require different drivers but have the same bus
address cannot be uniquely identified at runtime.
- A mainboard may be designed with multiple daughter board combinations
which contain devices and configurations that cannot be detected.
- While presence detect GPIOs are a convenient way for a single device
presence, they are unable to distinguish between different devices so
it can require a large number of GPIOs to support relatively few
options.
- I2C peripherals that require different drivers but have the same bus address cannot be
uniquely identified at runtime.
- A mainboard may be designed with multiple daughter board combinations which contain devices
and configurations that cannot be detected.
- While presence detect GPIOs are a convenient way for a single device presence, they are
unable to distinguish between different devices so it can require a large number of GPIOs to
support relatively few options.
This presence detection can impact different stages of boot:
### ACPI
Devices that are not present should not provide an ACPI device
indicating that they are present or the operating system may not be able
to handle it correctly.
The ACPI devices are largely driven by chips defined in the mainboard
`devicetree.cb` and the variant overridetree.cb. This means it is
important to be able to specify when a device is present or not directly
in `devicetree.cb` itself. Otherwise each mainboard needs custom code to
parse the tree and disable unused devices.
Devices that are not present should not provide an ACPI device indicating that they are
present or the operating system may not be able to handle it correctly.
The ACPI devices are largely driven by chips defined in the mainboard `devicetree.cb` and
the variant overridetree.cb. This means it is important to be able to specify when a device
is present or not directly in `devicetree.cb` itself. Otherwise each mainboard needs custom
code to parse the tree and disable unused devices.
### GPIO
GPIOs with multiple functions may need to be configured correctly
depending on the attached device. Given the wide variety of GPIO
configuration possibilities it is not feasible to specify all
combinations directly in `devicetree.cb` and it is best left to code
provided by the mainboard.
GPIOs with multiple functions may need to be configured correctly depending on the attached
device. Given the wide variety of GPIO configuration possibilities it is not feasible to
specify all combinations directly in `devicetree.cb` and it is best left to code provided by
the mainboard.
### FSP UPD
Enabling and disabling devices may require altering FSP UPD values that
are provided to the various stages of FSP. These options are also not
easy to specify multiple times for different configurations in
`devicetree.cb` and can be provided by the mainboard as code.
Enabling and disabling devices may require altering FSP UPD values that are provided to the
various stages of FSP. These options are also not easy to specify multiple times for
different configurations in `devicetree.cb` and can be provided by the mainboard as code.
## Firmware Configuration Interface
The firmware configuration interface can be enabled by selecting
`CONFIG_FW_CONFIG` and also providing a source for the value by defining
an additional Kconfig option defined below.
If the firmware configuration interface is disabled via Kconfig then all
probe attempts will return true.
The firmware configuration interface can be enabled by selecting `CONFIG_FW_CONFIG` and also
providing a source for the value by defining an additional Kconfig option defined below.
If the firmware configuration interface is disabled via Kconfig then all probe attempts will
return true.
## Firmware Configuration Value
The 64-bit value used as the firmware configuration bitmask is meant to
be determined at runtime but could also be defined at compile time if
needed.
There are two supported sources for providing this information to
coreboot.
The 64-bit value used as the firmware configuration bitmask is meant to be determined at runtime
but could also be defined at compile time if needed.
There are two supported sources for providing this information to coreboot.
### CBFS
The value can be provided with a 64-bit raw value in CBFS that is read
by coreboot. The value can be set at build time but also adjusted in an
existing image with `cbfstool`.
The value can be provided with a 64-bit raw value in CBFS that is read by coreboot. The value
can be set at build time but also adjusted in an existing image with `cbfstool`.
To enable this select the `CONFIG_FW_CONFIG_CBFS` option in the build
configuration and add a raw 64-bit value to CBFS with the name of the
current prefix at `CONFIG_FW_PREFIX/fw_config`.
When `fw_config_probe_device()` or `fw_config_probe()` is called it will
look for the specified file in CBFS use the value it contains when
matching fields and options.
To enable this select the `CONFIG_FW_CONFIG_CBFS` option in the build configuration and add a
raw 64-bit value to CBFS with the name of the current prefix at `CONFIG_FW_PREFIX/fw_config`.
When `fw_config_probe_device()` or `fw_config_probe()` is called it will look for the specified
file in CBFS use the value it contains when matching fields and options.
### Embedded Controller
Google ChromeOS devices support an Embedded Controller interface for
reading and writing the firmware configuration value, along with other
board-specific information. It is possible for coreboot to read this
value at boot on systems that support this feature.
Google ChromeOS devices support an Embedded Controller interface for reading and writing the
firmware configuration value, along with other board-specific information. It is possible for
coreboot to read this value at boot on systems that support this feature.
This option is selected by default for the mainboards that use it with
`CONFIG_FW_CONFIG_CHROME_EC_CBI` and it is not typically necessary to
adjust the value. It is possible by enabling the CBFS source and
coreboot will look in CBFS first for a valid value before asking the
embedded controller.
`CONFIG_FW_CONFIG_CHROME_EC_CBI` and it is not typically necessary to adjust the value. It is
possible by enabling the CBFS source and coreboot will look in CBFS first for a valid value
before asking the embedded controller.
It is also possible to adjust the value in the embedded controller
*(after disabling write protection)* with the `ectool` command in a
ChromeOS environment.
It is also possible to adjust the value in the embedded controller *(after disabling write
protection)* with the `ectool` command in a ChromeOS environment.
For more information on the firmware configuration field on ChromeOS
devices see the Chromium documentation for [Firmware Config][1] and
[Board Info][2].
For more information on the firmware configuration field on ChromeOS devices see the Chromium
documentation for [Firmware Config][1] and [Board Info][2].
[1]: http://chromium.googlesource.com/chromiumos/docs/+/HEAD/design_docs/firmware_config.md
[2]: http://chromium.googlesource.com/chromiumos/docs/+/HEAD/design_docs/cros_board_info.md
## Firmware Configuration Table
The firmware configuration table itself is defined in the mainboard
`devicetree.cb` with special tokens for defining fields and options.
The firmware configuration table itself is defined in the mainboard `devicetree.cb` with
special tokens for defining fields and options.
The table itself is enclosed in a `fw_config` token and terminated with
`end` and it contains a mix of field and option definitions.
The table itself is enclosed in a `fw_config` token and terminated with `end` and it contains
a mix of field and option definitions.
Each field is defined by providing the field name and the start and end
bit marking the exact location in the bitmask. Field names must be at
least three characters long in order to satisfy the sconfig parser
requirements and they must be unique with non-overlapping masks.
Each field is defined by providing the field name and the start and end bit marking the exact
location in the bitmask. Field names must be at least three characters long in order to
satisfy the sconfig parser requirements and they must be unique with non-overlapping masks.
```text
field <name> <start-bit> <end-bit> [option...] end
```
field <name> <start-bit> <end-bit> [option...] end
For single-bit fields only one number is needed:
```text
field <name> <bit> [option...] end
```
field <name> <bit> [option...] end
A field definition can also contain multiple sets of bit masks, which
can be dis-contiguous. They are treated as if they are contiguous when
defining option values. This allows for extending fields even after the
bits after its current masks are occupied.
A field definition can also contain multiple sets of bit masks, which can be dis-contiguous.
They are treated as if they are contiguous when defining option values. This allows for
extending fields even after the bits after its current masks are occupied.
```text
field <name> <start-bit0> <end-bit0> | <start-bit1> <end-bit1> | ...
```
field <name> <start-bit0> <end-bit0> | <start-bit1> <end-bit1> | ...
For example, if more audio options need to be supported:
```text
field AUDIO 3 3
option AUDIO_0 0
option AUDIO_1 1
end
field OTHER 4 4
...
end
```
field AUDIO 3 3
option AUDIO_0 0
option AUDIO_1 1
end
field OTHER 4 4
...
end
the following can be done:
```text
field AUDIO 3 3 | 5 5
option AUDIO_FOO 0
option AUDIO_BLAH 1
option AUDIO_BAR 2
option AUDIO_BAZ 3
end
field OTHER 4 4
...
end
```
field AUDIO 3 3 | 5 5
option AUDIO_FOO 0
option AUDIO_BLAH 1
option AUDIO_BAR 2
option AUDIO_BAZ 3
end
field OTHER 4 4
...
end
In that case, the AUDIO masks are extended like so:
```c
#define FW_CONFIG_FIELD_AUDIO_MASK 0x28
#define FW_CONFIG_FIELD_AUDIO_OPTION_AUDIO_FOO_VALUE 0x0
#define FW_CONFIG_FIELD_AUDIO_OPTION_AUDIO_BLAH_VALUE 0x8
#define FW_CONFIG_FIELD_AUDIO_OPTION_AUDIO_BAR_VALUE 0x20
#define FW_CONFIG_FIELD_AUDIO_OPTION_AUDIO_BAz_VALUE 0x28
```
#define FW_CONFIG_FIELD_AUDIO_MASK 0x28
#define FW_CONFIG_FIELD_AUDIO_OPTION_AUDIO_FOO_VALUE 0x0
#define FW_CONFIG_FIELD_AUDIO_OPTION_AUDIO_BLAH_VALUE 0x8
#define FW_CONFIG_FIELD_AUDIO_OPTION_AUDIO_BAR_VALUE 0x20
#define FW_CONFIG_FIELD_AUDIO_OPTION_AUDIO_BAz_VALUE 0x28
Each `field` definition starts a new block that can be composed of zero
or more field options, and it is terminated with `end`.
Each `field` definition starts a new block that can be composed of zero or more field options,
and it is terminated with `end`.
Inside the field block the options can be defined by providing the
option name and the field value that this option represents when the bit
offsets are used to apply a mask and shift. Option names must also be at
least three characters for the sconfig parser.
Inside the field block the options can be defined by providing the option name and the field
value that this option represents when the bit offsets are used to apply a mask and shift.
Option names must also be at least three characters for the sconfig parser.
```text
option <name> <value>
```
option <name> <value>
It is possible for there to be multiple `fw_config` blocks and for
subsequent `field` blocks to add additional `option` definitions to the
existing field. These subsequent definitions should not provide the
field bitmask as it has already been defined earlier in the file and
It is possible for there to be multiple `fw_config` blocks and for subsequent `field` blocks
to add additional `option` definitions to the existing field. These subsequent definitions
should not provide the field bitmask as it has already been defined earlier in the file and
this is just matching an existing field by name.
```text
field <name> [option...] end
```
field <name> [option...] end
This allows a baseboard to define the major fields and options in
`devicetree.cb` and a board variant to add specific options to fields in
or define new fields in the unused bitmask in `overridetree.cb`.
It is not possible to redefine a field mask or override the value of an
existing option this way, only to add new options to a field or new
fields to the table.
This allows a baseboard to define the major fields and options in `devicetree.cb` and a board
variant to add specific options to fields in or define new fields in the unused bitmask in
`overridetree.cb`.
It is not possible to redefine a field mask or override the value of an existing option this
way, only to add new options to a field or new fields to the table.
### Firmware Configuration Table Example
In this example a baseboard defines a simple boolean feature that is
enabled or disabled depending on the value of bit 0, and a field at bits
1-2 that indicates which daughter board is attached.
The baseboard itself defines one daughter board and the variant adds two
more possibilities. This way each variant can support multiple possible
daughter boards in addition to the one that was defined by the
baseboard.
In this example a baseboard defines a simple boolean feature that is enabled or disabled
depending on the value of bit 0, and a field at bits 1-2 that indicates which daughter board
is attached.
The baseboard itself defines one daughter board and the variant adds two more possibilities.
This way each variant can support multiple possible daughter boards in addition to the one
that was defined by the baseboard.
#### devicetree.cb
```text
fw_config
field FEATURE 0
option DISABLED 0
option ENABLED 1
fw_config
field FEATURE 0
option DISABLED 0
option ENABLED 1
end
field DAUGHTER_BOARD 1 2
option NONE 0
option REFERENCE_DB 1
end
end
field DAUGHTER_BOARD 1 2
option NONE 0
option REFERENCE_DB 1
end
end
```
#### overridetree.cb
```text
fw_config
field DAUGHTER_BOARD
option VARIANT_DB_ONE 2
option VARIANT_DB_TWO 3
fw_config
field DAUGHTER_BOARD
option VARIANT_DB_ONE 2
option VARIANT_DB_TWO 3
end
end
end
```
The result of this table defined in `devicetree.cb` is a list of
constants that can be used to check if fields match the firmware
configuration options determined at runtime with a simple check of the
field mask and the option value.
The result of this table defined in `devicetree.cb` is a list of constants that can be used
to check if fields match the firmware configuration options determined at runtime with a
simple check of the field mask and the option value.
#### static.h
@ -305,96 +246,73 @@ field mask and the option value.
#define FW_CONFIG_FIELD_DAUGHTER_BOARD_OPTION_VARIANT_DB_TWO_VALUE 0x00000006
```
## Device Probing
One use of the firmware configuration interface in devicetree is to
allow device probing to be specified directly with the devices
themselves. A new `probe` token is introduced to allow a device to be
probed by field and option name. Multiple `probe` entries may be present
for each device and any successful probe will consider the device to be
present.
One use of the firmware configuration interface in devicetree is to allow device probing to be
specified directly with the devices themselves. A new `probe` token is introduced to allow a
device to be probed by field and option name. Multiple `probe` entries may be present for
each device and any successful probe will consider the device to be present.
### Probing Example
Continuing with the previous example this device would be considered
present if the field `DAUGHTER_BOARD` was set to either `VARIANT_DB_ONE`
or `VARIANT_DB_TWO`:
Continuing with the previous example this device would be considered present if the field
`DAUGHTER_BOARD` was set to either `VARIANT_DB_ONE` or `VARIANT_DB_TWO`:
#### overridetree.cb
```text
chip drivers/generic/example
device generic 0 on
probe DAUGHTER_BOARD VARIANT_DB_ONE
probe DAUGHTER_BOARD VARIANT_DB_TWO
chip drivers/generic/example
device generic 0 on
probe DAUGHTER_BOARD VARIANT_DB_ONE
probe DAUGHTER_BOARD VARIANT_DB_TWO
end
end
end
```
If the field were set to any other option, including `NONE` and
`REFERENCE_DB` and any undefined value then the device would be
disabled.
If the field were set to any other option, including `NONE` and `REFERENCE_DB` and any
undefined value then the device would be disabled.
### Probe Overrides
When a device is declared with a probe in the baseboard `devicetree.cb`
and the same device is also present in the `overridetree.cb` then the
probing information from the baseboard is discarded and the override
device must provide all necessary probing information.
When a device is declared with a probe in the baseboard `devicetree.cb` and the same device
is also present in the `overridetree.cb` then the probing information from the baseboard
is discarded and the override device must provide all necessary probing information.
In this example a device is listed in the baseboard with
`DAUGHTER_BOARD` field probing for `REFERENCE_DB` as a field option, It
is also defined as an override device with the field probing for the
`VARIANT_DB_ONE` option instead.
In this case only the probe listed in the override is checked and a
field option of `REFERENCE_DB` will not mark this device present. If
both options are desired then the override device must list both. This
allows an override device to remove a probe entry that was defined in
the baseboard.
In this example a device is listed in the baseboard with `DAUGHTER_BOARD` field probing for
`REFERENCE_DB` as a field option, It is also defined as an override device with the field
probing for the `VARIANT_DB_ONE` option instead.
In this case only the probe listed in the override is checked and a field option of
`REFERENCE_DB` will not mark this device present. If both options are desired then the
override device must list both. This allows an override device to remove a probe entry that
was defined in the baseboard.
#### devicetree.cb
```text
chip drivers/generic/example
device generic 0 on
probe DAUGHTER_BOARD REFERENCE_DB
end
end
```
chip drivers/generic/example
device generic 0 on
probe DAUGHTER_BOARD REFERENCE_DB
end
end
#### overridetree.cb
```text
chip drivers/generic/example
device generic 0 on
probe DAUGHTER_BOARD VARIANT_DB_ONE
end
end
```
chip drivers/generic/example
device generic 0 on
probe DAUGHTER_BOARD VARIANT_DB_ONE
end
end
### Automatic Device Probing
At boot time the firmware configuration interface will walk the device
tree and apply any probe entries that were defined in `devicetree.cb`.
This probing takes effect before the `BS_DEV_ENUMERATE` step during the
boot state machine in ramstage.
At boot time the firmware configuration interface will walk the device tree and apply any
probe entries that were defined in `devicetree.cb`. This probing takes effect before the
`BS_DEV_ENUMERATE` step during the boot state machine in ramstage.
Devices that have a probe list but do do not find a match are disabled
by setting `dev->enabled = 0` but the chip `enable_dev()` and device
`enable()` handlers will still be executed to allow any device disable
code to execute.
The result of this probe definition is to provide an array of structures
describing each field and option to check.
Devices that have a probe list but do do not find a match are disabled by setting
`dev->enabled = 0` but the chip `enable_dev()` and device `enable()` handlers will still
be executed to allow any device disable code to execute.
The result of this probe definition is to provide an array of structures describing each
field and option to check.
#### fw_config.h
@ -407,43 +325,40 @@ describing each field and option to check.
* @value: Value of the option within the mask.
*/
struct fw_config {
const char *field_name;
const char *option_name;
uint64_t mask;
uint64_t value;
const char *field_name;
const char *option_name;
uint64_t mask;
uint64_t value;
};
```
#### static.c
```c
STORAGE struct fw_config __devN_probe_list[] = {
{
.field_name = FW_CONFIG_FIELD_DAUGHTER_BOARD_NAME,
.option_name = FW_CONFIG_FIELD_DAUGHTER_BOARD_OPTION_VARIANT_DB_ONE_NAME,
.mask = FW_CONFIG_FIELD_DAUGHTER_BOARD_MASK,
.value = FW_CONFIG_FIELD_DAUGHTER_BOARD_OPTION_VARIANT_DB_ONE_VALUE
},
{
.field_name = FW_CONFIG_FIELD_DAUGHTER_BOARD_NAME,
.option_name = FW_CONFIG_FIELD_DAUGHTER_BOARD_OPTION_VARIANT_DB_TWO_NAME,
.mask = FW_CONFIG_FIELD_DAUGHTER_BOARD_MASK,
.value = FW_CONFIG_FIELD_DAUGHTER_BOARD_OPTION_VARIANT_DB_TWO_VALUE
},
{ }
{
.field_name = FW_CONFIG_FIELD_DAUGHTER_BOARD_NAME,
.option_name = FW_CONFIG_FIELD_DAUGHTER_BOARD_OPTION_VARIANT_DB_ONE_NAME,
.mask = FW_CONFIG_FIELD_DAUGHTER_BOARD_MASK,
.value = FW_CONFIG_FIELD_DAUGHTER_BOARD_OPTION_VARIANT_DB_ONE_VALUE
},
{
.field_name = FW_CONFIG_FIELD_DAUGHTER_BOARD_NAME,
.option_name = FW_CONFIG_FIELD_DAUGHTER_BOARD_OPTION_VARIANT_DB_TWO_NAME,
.mask = FW_CONFIG_FIELD_DAUGHTER_BOARD_MASK,
.value = FW_CONFIG_FIELD_DAUGHTER_BOARD_OPTION_VARIANT_DB_TWO_VALUE
},
{ }
};
```
### Runtime Probing
The device driver probing allows for seamless integration with the
mainboard but it is only effective in ramstage and for specific devices
declared in devicetree.cb. There are other situations where code may
need to probe or check the value of a field in romstage or at other
points in ramstage. For this reason it is also possible to use the
firmware configuration interface directly.
The device driver probing allows for seamless integration with the mainboard but it is only
effective in ramstage and for specific devices declared in devicetree.cb. There are other
situations where code may need to probe or check the value of a field in romstage or at other
points in ramstage. For this reason it is also possible to use the firmware configuration
interface directly.
```c
/**
@ -457,21 +372,18 @@ bool fw_config_probe(const struct fw_config *match);
The argument provided to this function can be created from a macro for easy use:
```text
FW_CONFIG(field, option)
```
FW_CONFIG(field, option)
This example has a mainboard check if a feature is disabled and set an
FSP UPD before memory training. This example expects that the default
value of this `register` is set to `true` in `devicetree.cb` and this
code is disabling that feature before FSP is executed.
This example has a mainboard check if a feature is disabled and set an FSP UPD before memory
training. This example expects that the default value of this `register` is set to `true` in
`devicetree.cb` and this code is disabling that feature before FSP is executed.
```c
#include <fw_config.h>
void mainboard_memory_init_params(FSPM_UPD *mupd)
{
if (fw_config_probe(FW_CONFIG(FEATURE, DISABLED))
mupd->ExampleFeature = false;
if (fw_config_probe(FW_CONFIG(FEATURE, DISABLED))
mupd->ExampleFeature = false;
}
```

View file

@ -11,7 +11,4 @@ ABI data consumption <abi-data-consumption.md>
Timestamps <timestamp.md>
Firmware Configuration Interface <fw_config.md>
Relocatable Modules <rmodules.md>
Timers, Stopwatch, and Delays <stopwatch.md>
Threads <threads.md>
Ramstage Bootstates & Bootstate Callbacks <ramstage_bootstates.md>
```

View file

@ -1,514 +0,0 @@
# coreboot Ramstage Bootstates & Bootstate Callbacks
## Introduction
The coreboot boot process is divided into several discrete phases, one
of which is **ramstage**. Ramstage is the phase where the main hardware
initialization and device setup occurs after memory initialization.
Within ramstage, a state machine called the **bootstate machine**
manages the sequence of operations needed to initialize the system,
configure devices, and prepare to load and execute the payload (such as
a bootloader, operating system, or firmware utility).
The bootstate machine provides a structured and extensible way to
organize code execution during the boot process. It allows for clear
separation of concerns between different initialization phases and
provides hooks for component-specific code to run at well-defined
points.
**Important Note:** The exact execution order of multiple callbacks
registered for the same state and sequence (entry/exit) is not
guaranteed. This means that you cannot depend on one call for the
state/sequence in any other calls to the same state/sequence. If this
ordering is required, join the calls to the two functions into a single
function which specifies the order and create a callback to call the
top-level function instead of the two individual callbacks.
## Bootstate Machine Architecture
The bootstate machine's public API is defined in
`src/include/bootstate.h`, and its core implementation resides in
`src/lib/hardwaremain.c`. At its core, it consists of:
1. A series of sequential states that represent phases of the boot process
2. A mechanism for callback registration to execute code during state transitions
3. A framework for blocking and unblocking state transitions
4. Timing and debugging facilities to measure and report performance during boot
### Key Data Structures
The primary public data structure for interacting with the bootstate
machine is `struct boot_state_callback`. The internal implementation
also uses `struct boot_state` and `struct boot_phase`.
#### Boot State Callback (Public API)
Callbacks that run during state transitions are defined by this
structure in `src/include/bootstate.h`:
```c
struct boot_state_callback {
void *arg; // Argument to pass to the callback
void (*callback)(void *arg); // Function pointer to the callback
struct boot_state_callback *next; // Next callback in linked list (internal use)
#if CONFIG(DEBUG_BOOT_STATE)
const char *location; // Source location for debugging
#endif
};
```
#### Boot State Sequence (Public API)
The boot state sequence type, defined in `src/include/bootstate.h`,
specifies when a callback should run relative to the state's main
action:
```c
typedef enum {
BS_ON_ENTRY, // Execute before state function
BS_ON_EXIT // Execute after state function
} boot_state_sequence_t;
```
#### Boot State (Internal Implementation)
The main internal data structure in `src/lib/hardwaremain.c` is
`struct boot_state`, which defines a single state in the bootstate
machine:
```c
struct boot_state {
const char *name; // Human-readable name of the state
boot_state_t id; // Enumerated identifier for the state
u8 post_code; // POST code to output during state execution
struct boot_phase phases[2]; // Entry and exit phases (internal use)
boot_state_t (*run_state)(void *arg); // Function to execute during the state
void *arg; // Argument to pass to the run_state function
int num_samples; // Counter for timing samples (internal use)
bool complete; // Flag indicating if state has completed (internal use)
};
```
#### Boot Phase (Internal Implementation)
Each boot state has two internal phases ("entry" and "exit") represented
by `struct boot_phase` in `src/lib/hardwaremain.c`:
```c
struct boot_phase {
struct boot_state_callback *callbacks; // Linked list of callbacks
int blockers; // Counter for blocking state transition
};
```
## Bootstate Sequence
The bootstate machine defines the following sequence of states, executed
in order by the `bs_walk_state_machine` function in
`src/lib/hardwaremain.c`. The sequence is defined by the `boot_state_t`
enum in `src/include/bootstate.h`:
1. **BS_PRE_DEVICE**: Initial state before any device operations begin
2. **BS_DEV_INIT_CHIPS**: Early chip initialization for critical components
3. **BS_DEV_ENUMERATE**: Device enumeration (discovering devices on buses)
4. **BS_DEV_RESOURCES**: Resource allocation for devices
5. **BS_DEV_ENABLE**: Enabling devices that were discovered
6. **BS_DEV_INIT**: Device initialization
7. **BS_POST_DEVICE**: All device operations have been completed
8. **BS_OS_RESUME_CHECK**: Check if we're resuming from a sleep state
9. **BS_OS_RESUME**: Handle OS resume process (if needed)
10. **BS_WRITE_TABLES**: Write system tables (e.g., ACPI, SMBIOS)
11. **BS_PAYLOAD_LOAD**: Load the payload into memory
12. **BS_PAYLOAD_BOOT**: Boot the payload
This sequence forms the backbone of the ramstage execution flow. Each
state performs a specific task, runs associated callbacks, and
transitions to the next state upon completion, unless blocked.
## Bootstate Details
### BS_PRE_DEVICE
**Purpose**: Serves as the initial state before any device tree
operations begin.
**Key Functions**:
- `bs_pre_device()`: Sets up initial environment and transitions to next
state.
**Usage**: This state is used for initializing core components that need
to be set up before any device operations. Examples include:
- Setting up global NVRAM variables
- Initializing debugging facilities
- Preparing ACPI tables or other critical system structures
### BS_DEV_INIT_CHIPS
**Purpose**: Initializes critical chips early in the boot process.
**Key Functions**:
- `bs_dev_init_chips()`: Calls `dev_initialize_chips()` to initialize
all chips in the device tree.
**Notes**: Chip initialization can disable unused devices, which is why
it happens before device enumeration.
### BS_DEV_ENUMERATE
**Purpose**: Discovers devices in the system.
**Key Functions**:
- `bs_dev_enumerate()`: Calls `dev_enumerate()` to probe and identify
devices.
**Notes**: During this phase, the system scans buses and detects
connected devices.
### BS_DEV_RESOURCES
**Purpose**: Allocates and assigns resources (I/O, memory, IRQs) to
devices.
**Key Functions**:
- `bs_dev_resources()`: Calls `dev_configure()` to compute and assign
bus resources.
**Notes**: Resource allocation resolves conflicts and ensures each
device has the resources it needs.
### BS_DEV_ENABLE
**Purpose**: Enables devices in the system.
**Key Functions**:
- `bs_dev_enable()`: Calls `dev_enable()` to enable devices on the bus.
**Notes**: Some devices may be selectively disabled based on hardware
configuration or policy.
### BS_DEV_INIT
**Purpose**: Initializes enabled devices.
**Key Functions**:
- `bs_dev_init()`: Calls `dev_initialize()` to initialize devices on the
bus.
**Notes**: This state performs device-specific initialization routines
for all enabled devices.
### BS_POST_DEVICE
**Purpose**: Final state after all device operations have completed.
**Key Functions**:
- `bs_post_device()`: Calls `dev_finalize()` to complete any final
device operations.
**Notes**: This state serves as a checkpoint that all device
initialization is complete.
### BS_OS_RESUME_CHECK
**Purpose**: Checks if the system should resume from a sleep state.
**Key Functions**:
- `bs_os_resume_check()`: Looks for a wake vector to determine if resume
is needed.
**Notes**: This state branches the boot flow based on whether the system
is resuming from a sleep state.
### BS_OS_RESUME
**Purpose**: Handles the OS resume process.
**Key Functions**:
- `bs_os_resume()`: Calls `acpi_resume()` with the wake vector to resume
the OS.
**Notes**: After successful resume, control is transferred to the OS and
does not return to coreboot.
### BS_WRITE_TABLES
**Purpose**: Writes configuration tables for the payload or OS.
**Key Functions**:
- `bs_write_tables()`: Calls `write_tables()` to generate system tables.
**Notes**: Tables include ACPI, SMBIOS, and other system configuration
data.
### BS_PAYLOAD_LOAD
**Purpose**: Loads the payload into memory.
**Key Functions**:
- `bs_payload_load()`: Calls `payload_load()` to load the payload.
**Notes**: The payload could be a bootloader, an operating system kernel,
or a firmware utility.
### BS_PAYLOAD_BOOT
**Purpose**: Final state that boots the loaded payload.
**Key Functions**:
- `bs_payload_boot()`: Calls `payload_run()` to execute the payload.
**Notes**: After successful execution, control is transferred to the
payload and does not return to coreboot. If execution returns (which
indicates an error), a boot failure message is printed.
## Driving the State Machine
The state machine is driven by the `main()` function in
`src/lib/hardwaremain.c`. After initial setup (like initializing the
console and CBMEM), it calls `bs_walk_state_machine()`.
`bs_walk_state_machine()` loops through the defined boot states:
1. It identifies the current state.
2. Runs all `BS_ON_ENTRY` callbacks for that state.
3. Executes the state's specific function (e.g., `bs_dev_enumerate()`).
4. Runs all `BS_ON_EXIT` callbacks for that state.
5. Transitions to the next state returned by the state function.
This loop continues until the final state (`BS_PAYLOAD_BOOT` or
`BS_OS_RESUME`) transfers control away from coreboot.
## External Functions (Public API)
The bootstate machine provides several functions in
`src/include/bootstate.h` for interacting with states:
### Callback Registration
```c
int boot_state_sched_on_entry(struct boot_state_callback *bscb, boot_state_t state_id);
```
Schedules a callback to run when entering a state (`BS_ON_ENTRY`).
```c
int boot_state_sched_on_exit(struct boot_state_callback *bscb, boot_state_t state_id);
```
Schedules a callback to run when exiting a state (`BS_ON_EXIT`).
### State Transition Control
```c
int boot_state_block(boot_state_t state, boot_state_sequence_t seq);
```
Blocks a state transition from occurring after the specified sequence
(entry or exit callbacks). The transition will pause until the block is
removed.
```c
int boot_state_unblock(boot_state_t state, boot_state_sequence_t seq);
```
Removes a previously set block on a state transition.
### Static Callback Registration
For registering callbacks at compile time, use the `BOOT_STATE_INIT_ENTRY`
macro defined in `src/include/bootstate.h`:
```c
BOOT_STATE_INIT_ENTRY(state, when, func, arg)
```
This macro creates a static entry in a special section (`.bs_init`) of
the binary. These entries are processed early in `main()` by
`boot_state_schedule_static_entries()` to register the callbacks before
the state machine starts running.
## Configuration Options
The bootstate machine behavior can be modified through Kconfig options:
### DEBUG_BOOT_STATE
```
config DEBUG_BOOT_STATE
bool "Debug boot state machine"
default n
help
Control debugging of the boot state machine. When selected displays
the state boundaries in ramstage.
```
When enabled, this option causes the bootstate machine to output
debugging information via `printk`, including:
- State transition notifications (`Entering/Exiting <state> state.`)
- Callback execution details (address, source location, execution time)
- Timing information for state execution phases (entry, run, exit)
## Examples
### Adding a New Bootstate Callback
To register a function to be called when entering a specific state using
the static registration method:
```c
// Function to be called
static void my_init_function(void *arg)
{
// Initialization code
printk(BIOS_DEBUG, "My initialization running...\n");
}
// Register the callback at compile time
BOOT_STATE_INIT_ENTRY(BS_DEV_INIT, BS_ON_ENTRY, my_init_function, NULL);
```
### Runtime Callback Registration
For dynamic callback registration during runtime (e.g., within another
callback or state function):
```c
static void runtime_init(void *arg)
{
// Do something
}
void register_my_callbacks(void)
{
// Allocate or define a static callback structure
static struct boot_state_callback bscb = {
.callback = runtime_init,
.arg = NULL,
// .location is automatically handled if DEBUG_BOOT_STATE=y
};
// Schedule it
boot_state_sched_on_entry(&bscb, BS_DEV_ENABLE);
}
```
### Blocking State Transition
To temporarily block a state from progressing until a condition is met,
often used with timers:
```c
#include <timer.h> // Required for timer functions
static void wait_for_device(void *arg)
{
if (!device_is_ready()) {
// Block the transition *after* BS_DEV_INIT exits
boot_state_block(BS_DEV_INIT, BS_ON_EXIT);
// Schedule a function to check again later (e.g., after 100us)
// Assume schedule_timer exists and works appropriately
schedule_timer(check_device_ready, NULL, 100);
}
}
static void check_device_ready(void *arg)
{
if (device_is_ready()) {
// Device is ready, unblock the transition
boot_state_unblock(BS_DEV_INIT, BS_ON_EXIT);
} else {
// Still not ready, check again later
schedule_timer(check_device_ready, NULL, 100);
}
}
// Register the initial check to run when entering BS_DEV_INIT
BOOT_STATE_INIT_ENTRY(BS_DEV_INIT, BS_ON_ENTRY, wait_for_device, NULL);
```
## Best Practices
### When Working with Bootstates
1. **Choose the appropriate state**: Register callbacks at the earliest
state where all dependencies are guaranteed to be initialized, but no
earlier. Check the state descriptions and the functions called by
each state function (`bs_*`) in `hardwaremain.c`.
2. **Keep callbacks focused**: Each callback should perform a specific,
related task and avoid complex operations that might significantly
delay the boot process.
3. **Consider dependencies carefully**: Ensure any hardware, data
structures, or other resources your callback needs are available and
initialized at the chosen state and sequence (`BS_ON_ENTRY` vs.
`BS_ON_EXIT`).
4. **Do not rely on callback order**: Remember that the execution order
of callbacks within the same state and sequence is not guaranteed.
Callbacks should be self-contained and not depend on side effects from
other callbacks that might run before or after them in the same phase.
5. **Use blocking sparingly**: The blocking mechanism is powerful for
synchronization but can complicate the boot flow and make debugging
harder if overused. Always ensure a corresponding `boot_state_unblock`
call will eventually run.
6. **Leverage compile-time registration**: Prefer using
`BOOT_STATE_INIT_ENTRY` for callbacks whenever possible. It makes the
registration explicit and easier to find. Runtime registration is
necessary only when the need for the callback is determined dynamically.
7. **Debug with timestamps and `DEBUG_BOOT_STATE`**: Use the timestamp API
(`timestamp_add_now()`) and enable `DEBUG_BOOT_STATE` to measure
callback execution time, identify bottlenecks, and understand the
flow during development.
8. **Document state-specific behavior**: When adding callbacks, add
comments explaining why they are placed in a particular state and
sequence.
9. **Be careful with late states**: Avoid registering non-essential
callbacks in `BS_PAYLOAD_BOOT` or `BS_OS_RESUME`. Callbacks on
`BS_ON_EXIT` for these states are disallowed by compile-time asserts,
as coreboot is about to transfer control.
## Related Documentation
- [Boot Stages in coreboot](https://doc.coreboot.org/getting_started/architecture.html):
Overview of all coreboot boot stages.
## References
- `src/include/bootstate.h`: Public API definitions (callbacks, enums,
scheduling/blocking functions, static registration macro).
- `src/lib/hardwaremain.c`: Internal implementation (state machine driver,
state definitions, state functions).
- `src/ec/google/wilco/chip.c`: Example of bootstate callback usage.
- `src/mainboard/prodrive/hermes/mainboard.c`: Examples of mainboard-specific
bootstate callbacks.

View file

@ -35,24 +35,8 @@ One can split the rmodules in two different kinds:
1. coreboot stages (postcar, ramstage)
2. simple binaries (smm, smmstub, sipi\_vector)
There is one important difference in how they are handled:
The simple binaries are compiled into rmodules the same as coreboot
stages are, but the simple binaries are always directly linked to a
stage. Since rmodules are ELF files as well, we can easily link them
to the stages in which we need them (usually postcar or ramstage).
So they are not really separate modules anymore, but still retain
the ability to accept rmodule\_parameters.
Since the simple binaries are usually very small, linking them directly
into the stage (e.g. ramstage or postcar) avoids having to fetch them
from CBFS and running all that code to fetch a few hundred bytes of
code. So the build system handles them as follows:
1. create rmodule (which is an ELF file) from source files
2. remove all the ELF headers and sections that are not loadable using
`objcopy -O binary`
3. from this, create an object file, which usually has the self invented
.manual file extension, which can be linked to the appropriate stage
4. add the generated .manual file as "source" file to the stage we want
to link it to
They are actually handled the same by the build system and only differ
in the fact, that they are either coreboot stages or they are not.
In the end the ELF files will have three different ELF sections,
which are all created by the rmodtool.

View file

@ -1,910 +0,0 @@
# coreboot Timers, Stopwatch, Delays, and Associated Callbacks
## Introduction
coreboot provides several mechanisms for handling time, including
high-precision stopwatches for profiling, simple delay functions for
hardware timing, and a monotonic timer system that forms the foundation
for these features. It also supports scheduling timer callbacks for
deferred execution. These tools are crucial for performance
optimization, debugging, ensuring proper hardware timing, and managing
asynchronous events during the boot process.
This document describes the core monotonic timer, the delay functions
(`udelay`, `mdelay`, `delay`), the stopwatch API (`struct stopwatch`),
and the timer callback mechanism.
## Architecture Overview
The timing facilities are layered:
- **Platform Timer:** Hardware-specific implementations provide a raw
time source (e.g., LAPIC timer, Time Base register). These are often
abstracted by `timer_monotonic_get()`.
- **Monotonic Timer:** (`src/include/timer.h`, `src/lib/timer.c`)
Provides a consistent time source (`struct mono_time`) counting
microseconds since timer initialization. Requires
`CONFIG(HAVE_MONOTONIC_TIMER)`.
- **Delay Functions:** (`src/include/delay.h`, `src/lib/delay.c`,
`src/lib/timer.c`) Simple blocking delays (`udelay`, `mdelay`,
`delay`). The generic `udelay` uses the stopwatch API if yielding via
`thread_yield_microseconds()` is not performed.
- **Stopwatch API:** (`src/include/timer.h`) A lightweight wrapper
around the monotonic timer for measuring durations and handling
timeouts (`struct stopwatch`,`wait_us`,`wait_ms`).
- **Timer Callbacks:** (`src/include/timer.h`) Allows scheduling
functions to be called after a specified delay
(`struct timeout_callback`, `timer_sched_callback()`, `timers_run()`).
These APIs are generally designed to be thread-safe and usable across
different boot stages.
## Core Monotonic Timer
The foundation is the monotonic timer, enabled by
`CONFIG(HAVE_MONOTONIC_TIMER)`. It provides a time source that
continuously increases from an arbitrary starting point (usually near
timer initialization).
### Data Structures
#### struct mono_time
```c
struct mono_time {
uint64_t microseconds; // Time in microseconds since timer init
};
```
Represents a point in monotonic time. Direct field access outside core
timer code is discouraged; use helper functions.
### API Functions
#### timer_monotonic_get
```c
void timer_monotonic_get(struct mono_time *mt);
```
Retrieves the current monotonic time.
**Parameters:**
- `mt`: Pointer to a `struct mono_time` to store the current time.
**Preconditions:**
- `CONFIG(HAVE_MONOTONIC_TIMER)` must be enabled.
- The underlying platform timer must be functional. Platform
implementations may require an `init_timer()` call.
**Postconditions:**
- `mt` contains the current monotonic time in microseconds.
**Note:** If `CONFIG(HAVE_MONOTONIC_TIMER)` is *not* enabled, functions
relying on it (like stopwatch functions) will generally fall back to
basic behavior (e.g., returning 0 durations, immediate expiration
checks).
#### init_timer
```c
void init_timer(void);
```
Platform-specific timer initialization. The generic version in
`src/lib/timer.c` is a weak empty function
`__weak void init_timer(void) { /* do nothing */ }`. Platforms needing
explicit timer setup (e.g., configuring frequency, enabling the
counter) must provide their own strong implementation. Check platform
code (`src/cpu/`, `src/soc/`) for details.
#### `mono_time` Helper Functions
`src/include/timer.h` also provides several inline helper functions for
manipulating `struct mono_time` values:
- `mono_time_set_usecs()`, `mono_time_set_msecs()`: Set time.
- `mono_time_add_usecs()`, `mono_time_add_msecs()`: Add duration.
- `mono_time_cmp()`: Compare two times.
- `mono_time_after()`, `mono_time_before()`: Check time ordering.
- `mono_time_diff_microseconds()`: Calculate difference between two
times.
Refer to `src/include/timer.h` for their exact definitions.
## Delay Functions
coreboot provides simple functions for introducing delays.
### udelay
```c
void udelay(unsigned int usecs);
```
Delays execution for *at least* the specified number of microseconds.
**Parameters:**
- `usecs`: Number of microseconds to delay.
**Implementation Notes:**
- The generic implementation in `src/lib/timer.c` first attempts to
yield using `thread_yield_microseconds()` if `CONFIG(HAS_THREADS)` is
enabled. If yielding handles the required delay (function returns 0),
`udelay` returns immediately, allowing other threads to run.
- If `thread_yield_microseconds()` does not handle the delay (returns
non-zero), or if threading is disabled, the generic `udelay` falls
back to a busy-wait using the stopwatch API
(`stopwatch_init_usecs_expire()` and
`stopwatch_wait_until_expired()`).
- Architecture-specific implementations (e.g., in `src/arch/`) may
override the generic one for better precision or efficiency.
- Adds 1 microsecond internally to ensure the delay is *at least* the
requested duration.
**Preconditions:**
- If relying on the stopwatch fallback,
`CONFIG(HAVE_MONOTONIC_TIMER)` is needed.
- Underlying timer (if used) must be initialized (potentially via a
platform `init_timer()`).
- The delay value should be reasonable (overly large values might cause
issues or unexpected behavior depending on the implementation).
**Example:**
```c
#include <delay.h>
// Wait for 100 microseconds
udelay(100);
```
### mdelay
```c
void mdelay(unsigned int msecs);
```
Delays execution for *at least* the specified number of milliseconds.
**Parameters:**
- `msecs`: Number of milliseconds to delay.
**Implementation Notes:**
- The generic implementation in `src/lib/delay.c` simply calls
`udelay(1000)` in a loop `msecs` times.
- Therefore, it inherits the behavior of `udelay`, including the attempt
to yield first if `udelay` supports it.
**Preconditions:**
- Same as `udelay`.
**Example:**
```c
#include <delay.h>
// Wait for 50 milliseconds
mdelay(50);
```
### delay
```c
void delay(unsigned int secs);
```
Delays execution for *at least* the specified number of seconds.
**Parameters:**
- `secs`: Number of seconds to delay.
**Implementation Notes:**
- The generic implementation in `src/lib/delay.c` simply calls
`mdelay(1000)` in a loop `secs` times.
- Inherits the behavior of `mdelay` and `udelay`.
**Preconditions:**
- Same as `udelay`.
**Example:**
```c
#include <delay.h>
// Wait for 2 seconds
delay(2);
```
## Stopwatch API
The stopwatch API provides a convenient way to measure time durations
and implement timeouts based on the monotonic timer.
### Data Structures
#### struct stopwatch
```c
#include <timer.h> // For struct stopwatch and struct mono_time
struct stopwatch {
struct mono_time start; // Time when stopwatch was started or initialized
struct mono_time current; // Time when stopwatch was last ticked
struct mono_time expires; // Expiration time for timeout operations
};
```
Holds the state for a stopwatch instance.
### API Functions
#### Initialization Functions
##### stopwatch_init
```c
#include <timer.h>
static inline void stopwatch_init(struct stopwatch *sw);
```
Initializes a stopwatch structure. `start`, `current`, and `expires` are
all set to the current monotonic time. Use this when you only need to
measure elapsed duration from initialization.
**Parameters:**
- `sw`: Pointer to the stopwatch structure to initialize.
**Preconditions:**
- `sw` must point to valid memory.
- `CONFIG(HAVE_MONOTONIC_TIMER)` should be enabled for meaningful
timing.
**Postconditions:**
- The stopwatch is initialized.
##### stopwatch_init_usecs_expire
```c
#include <timer.h>
static inline void stopwatch_init_usecs_expire(struct stopwatch *sw, uint64_t us);
```
Initializes a stopwatch and sets an expiration time `us` microseconds
from now.
**Parameters:**
- `sw`: Pointer to the stopwatch structure.
- `us`: Timeout duration in microseconds.
**Preconditions:**
- `sw` must point to valid memory.
- `CONFIG(HAVE_MONOTONIC_TIMER)` should be enabled.
**Postconditions:**
- The stopwatch is initialized, and `expires` is set `us` microseconds
after `start`.
##### stopwatch_init_msecs_expire
```c
#include <timer.h>
static inline void stopwatch_init_msecs_expire(struct stopwatch *sw, uint64_t ms);
```
Initializes a stopwatch and sets an expiration time `ms` milliseconds
from now.
**Parameters:**
- `sw`: Pointer to the stopwatch structure.
- `ms`: Timeout duration in milliseconds.
**Preconditions:**
- `sw` must point to valid memory.
- `CONFIG(HAVE_MONOTONIC_TIMER)` should be enabled.
**Postconditions:**
- The stopwatch is initialized, and `expires` is set `ms` milliseconds
after `start`.
#### Time Measurement Functions
##### stopwatch_tick
```c
#include <timer.h>
static inline void stopwatch_tick(struct stopwatch *sw);
```
Updates the `current` time field in the stopwatch structure to the
current monotonic time. This is often called implicitly by other
stopwatch functions like `stopwatch_expired()` and
`stopwatch_duration_usecs()`.
**Parameters:**
- `sw`: Pointer to the stopwatch structure.
**Preconditions:**
- The stopwatch must be initialized.
- `CONFIG(HAVE_MONOTONIC_TIMER)` should be enabled.
##### stopwatch_expired
```c
#include <timer.h>
static inline int stopwatch_expired(struct stopwatch *sw);
```
Checks if the stopwatch's expiration time (`expires`) has passed. It
implicitly calls `stopwatch_tick()` to get the current time for
comparison.
**Parameters:**
- `sw`: Pointer to the stopwatch structure.
**Returns:**
- Non-zero (true) if `current` time >= `expires` time.
- Zero (false) otherwise.
**Preconditions:**
- The stopwatch must be initialized (preferably with an expiration
time).
- `CONFIG(HAVE_MONOTONIC_TIMER)` should be enabled.
##### stopwatch_wait_until_expired
```c
#include <timer.h>
static inline void stopwatch_wait_until_expired(struct stopwatch *sw);
```
Blocks (busy-waits) until the stopwatch expires by repeatedly calling
`stopwatch_expired()`.
**Parameters:**
- `sw`: Pointer to the stopwatch structure.
**Preconditions:**
- The stopwatch must be initialized with an expiration time.
- `CONFIG(HAVE_MONOTONIC_TIMER)` should be enabled.
**Postconditions:**
- The function returns only after the stopwatch has expired.
#### Duration Measurement Functions
##### stopwatch_duration_usecs
```c
#include <timer.h>
static inline int64_t stopwatch_duration_usecs(struct stopwatch *sw);
```
Returns the elapsed time in microseconds between `start` and `current`.
If `current` hasn't been updated since `stopwatch_init`, it implicitly
calls `stopwatch_tick()` first.
**Parameters:**
- `sw`: Pointer to the stopwatch structure.
**Returns:**
- Elapsed time in microseconds (`current` - `start`).
**Preconditions:**
- The stopwatch must be initialized.
- `CONFIG(HAVE_MONOTONIC_TIMER)` should be enabled for a meaningful
duration.
##### stopwatch_duration_msecs
```c
#include <timer.h>
static inline int64_t stopwatch_duration_msecs(struct stopwatch *sw);
```
Returns the elapsed time in milliseconds since the stopwatch was
started. It calls `stopwatch_duration_usecs()` and divides by 1000.
**Parameters:**
- `sw`: Pointer to the stopwatch structure.
**Returns:**
- Elapsed time in milliseconds.
**Preconditions:**
- The stopwatch must be initialized.
- `CONFIG(HAVE_MONOTONIC_TIMER)` should be enabled.
### Utility Macros
These macros combine stopwatch initialization and expiration checking with
a user-provided condition.
#### wait_us
```c
#include <timer.h>
#define wait_us(timeout_us, condition) ...
```
Waits until a condition becomes true or a timeout elapses, whichever
comes first. Internally uses a `struct stopwatch`.
**Parameters:**
- `timeout_us`: Timeout duration in microseconds.
- `condition`: A C expression that evaluates to true or false. The loop
continues as long as the condition is false and the timeout has not
expired.
**Returns:**
- 0: If the condition was still false when the timeout expired.
- >0: If the condition became true before the timeout. The return value
is the approximate number of microseconds waited (at least 1).
**Preconditions:**
- `CONFIG(HAVE_MONOTONIC_TIMER)` should be enabled.
#### wait_ms
```c
#include <timer.h>
#define wait_ms(timeout_ms, condition) ...
```
Similar to `wait_us`, but the timeout is specified in milliseconds.
**Parameters:**
- `timeout_ms`: Timeout duration in milliseconds.
- `condition`: C expression to wait for.
**Returns:**
- 0: If the condition was still false after the timeout.
- >0: If the condition became true before the timeout. The return value
is the approximate number of milliseconds waited (rounded up, at
least 1).
**Preconditions:**
- `CONFIG(HAVE_MONOTONIC_TIMER)` should be enabled.
## Key differences between `mdelay` and `wait_ms`
While both can be used to wait, they serve different purposes:
### Purpose and Use Case
- `mdelay`: Provides an *unconditional* delay for a fixed duration. The
generic implementation attempts to yield to other threads first (if
`CONFIG(HAS_THREADS)` is enabled via `udelay`), but it always waits
for (at least) the specified time, potentially using a busy-wait if
yielding doesn't occur. Primarily used for hardware timing
requirements or pacing operations.
- `wait_ms`: Provides a *conditional* wait. It waits for a specific C
expression (`condition`) to become true, but *only up to* a maximum
timeout duration. Used when polling for a status change or event, with
a safeguard against waiting indefinitely.
### When to Use Which
#### Use `mdelay` when:
- You need a guaranteed minimum delay (e.g., waiting for hardware to
settle after a register write).
- You are implementing a hardware initialization sequence with specific
timing requirements between steps.
- You want a simple pause, potentially allowing other threads to run if
the underlying `udelay` yields.
**Example:**
```c
#include <delay.h>
#include <arch/io.h> // For write_reg hypothetical function
// Initialize hardware with specific timing requirements
write_reg(REG_A, value);
mdelay(10); // Must wait (at least) 10ms after writing REG_A
write_reg(REG_B, another_value);
```
#### Use `wait_ms` when:
- You are waiting for a hardware status bit to change or a condition to
become true.
- You need to implement a timeout for an operation that might fail or
take too long.
- You want to know approximately how long you waited for the condition
to become true (via the return value).
**Example:**
```c
#include <timer.h>
#include <console/console.h>
#include <arch/io.h> // For read_reg hypothetical function
// Wait for hardware to become ready, but not forever
#define STATUS_REG 0x100
#define READY_BIT (1 << 0)
int64_t waited_ms = wait_ms(100, (read_reg(STATUS_REG) & READY_BIT));
if (waited_ms > 0) {
printk(BIOS_INFO, "Hardware ready after ~%lld ms\n", waited_ms);
} else {
printk(BIOS_ERR, "Timeout: Hardware failed to become ready within 100 ms\n");
}
```
### Performance Considerations
- `mdelay`: Generally simpler if the underlying `udelay` performs a
busy-wait. If it yields (`thread_yield_microseconds`), overhead depends
on the scheduler. Always waits for the full duration (approximately).
- `wait_ms`: Involves repeated condition checking and stopwatch
management (`stopwatch_expired`, which calls `timer_monotonic_get`),
adding overhead within the loop. However, it can return early if the
condition becomes true, potentially saving time compared to a fixed
`mdelay`.
### Error Handling / Feedback
- `mdelay`: Provides no feedback. It simply waits.
- `wait_ms`: Returns whether the condition was met within the timeout
and provides the approximate wait time if successful. This allows for
explicit timeout handling.
### Summary
Use `mdelay` for fixed, unconditional delays, potentially allowing
thread yielding. Use `wait_ms` for conditional waits with a timeout and
feedback on success or failure. Choose based on whether you need to poll
for a condition or simply need to pause execution.
## Timer Callbacks
coreboot provides a mechanism to schedule functions (callbacks) to be
executed after a certain time has elapsed. This requires
`CONFIG(TIMER_QUEUE)`.
### Data Structures
#### struct timeout_callback
```c
#include <timer.h>
struct timeout_callback {
void *priv; // Private data for the callback
void (*callback)(struct timeout_callback *tocb); // Function to call
/* Internal use by timer library: */
struct mono_time expiration; // Calculated expiration time
};
```
Represents a scheduled callback. The user initializes `priv` and
`callback`.
### API Functions
#### timer_sched_callback
```c
#include <timer.h>
int timer_sched_callback(struct timeout_callback *tocb, uint64_t us);
```
Schedules a callback function to run after a specified delay.
**Parameters:**
- `tocb`: Pointer to a `struct timeout_callback`. The `priv` and
`callback` fields must be set by the caller. The structure must
persist until the callback runs or is canceled (cancellation not
directly supported by API).
- `us`: Delay in microseconds from the time of this call until the
callback should run.
**Returns:**
- 0: Success.
- <0: Error (e.g., timer queue full, invalid arguments).
**Preconditions:**
- `CONFIG(TIMER_QUEUE)` and `CONFIG(HAVE_MONOTONIC_TIMER)` must be
enabled.
- `tocb` must point to a valid structure with `callback` assigned.
**Postconditions:**
- The callback is added to a queue, to be executed when `timers_run()`
is called after the expiration time.
#### timers_run
```c
#include <timer.h>
int timers_run(void);
```
Checks the timer callback queue and executes any callbacks whose
expiration time has passed. This function needs to be called
periodically from the main execution flow (e.g., in a boot state loop
or idle task) for callbacks to be processed.
**Returns:**
- 1: If callbacks were run or are still pending in the queue.
- 0: If the queue is empty and no callbacks were run.
**Preconditions:**
- `CONFIG(TIMER_QUEUE)` and `CONFIG(HAVE_MONOTONIC_TIMER)` must be
enabled.
**Usage:**
Typically called in loops where deferred work might need processing:
```c
#include <timer.h>
// Example main loop structure
while (some_condition) {
// ... do other work ...
// Process any expired timer callbacks
timers_run();
// ... potentially yield or sleep ...
}
```
## Usage Examples
### Basic Timing Measurement Example
```c
#include <timer.h>
#include <console/console.h>
struct stopwatch sw;
stopwatch_init(&sw);
// ---> Code section to measure start
// ... perform some operations ...
// ---> Code section to measure end
// stopwatch_duration_usecs implicitly ticks the stopwatch if needed
int64_t duration_us = stopwatch_duration_usecs(&sw);
printk(BIOS_INFO, "Operation took %lld microseconds\n", duration_us);
// Or in milliseconds
int64_t duration_ms = stopwatch_duration_msecs(&sw);
printk(BIOS_INFO, "Operation took %lld milliseconds\n", duration_ms);
```
### Timeout Operation (Polling) Example
```c
#include <timer.h>
#include <console/console.h>
#include <stdint.h> // For uint8_t example
// Hypothetical hardware status check
extern uint8_t check_hardware_status(void);
#define HW_READY (1 << 0)
struct stopwatch sw;
// Initialize stopwatch with a 100 millisecond timeout
stopwatch_init_msecs_expire(&sw, 100);
uint8_t status = 0;
while (!(status & HW_READY)) {
status = check_hardware_status();
if (stopwatch_expired(&sw)) {
printk(BIOS_ERR, "Operation timed out waiting for HW_READY\n");
// Handle timeout error...
status = 0; // Indicate failure perhaps
break;
}
// Optional: Add a small delay here to avoid busy-spinning the CPU excessively
// udelay(10); // e.g., wait 10us between checks
}
if (status & HW_READY) {
printk(BIOS_DEBUG, "Hardware became ready.\n");
// Continue with operation...
}
```
### Waiting for a Condition (Using `wait_ms`) Example
```c
#include <timer.h>
#include <console/console.h>
#include <stdint.h> // For uint8_t example
// Hypothetical hardware status check
extern uint8_t check_hardware_status(void);
#define HW_READY (1 << 0)
// Wait up to 100ms for the HW_READY bit
int64_t waited_ms = wait_ms(100, (check_hardware_status() & HW_READY));
if (waited_ms > 0) {
printk(BIOS_INFO, "Condition met: HW_READY asserted after ~%lld ms\n", waited_ms);
// Continue...
} else {
printk(BIOS_ERR, "Timeout: HW_READY not asserted within 100 ms\n");
// Handle timeout error...
}
```
### Scheduling a Timer Callback Example
```c
#include <timer.h>
#include <console/console.h>
// Data structure for our callback context
struct my_callback_data {
int counter;
const char *message;
};
// The callback function
static void my_callback_handler(struct timeout_callback *tocb)
{
struct my_callback_data *data = tocb->priv;
printk(BIOS_INFO, "Callback executed! Message: %s, Counter: %d\n",
data->message, data->counter);
// Note: 'tocb' can be reused here to reschedule if needed,
// or the memory it points to can be freed if dynamically allocated.
}
// Somewhere in initialization code:
static struct timeout_callback my_timer;
static struct my_callback_data my_data;
void schedule_my_task(void)
{
my_data.counter = 42;
my_data.message = "Hello from timer";
my_timer.priv = &my_data;
my_timer.callback = my_callback_handler;
// Schedule the callback to run after 500 milliseconds (500,000 us)
int rc = timer_sched_callback(&my_timer, 500 * 1000);
if (rc == 0) {
printk(BIOS_DEBUG, "Scheduled my_callback_handler successfully.\n");
} else {
printk(BIOS_ERR, "Failed to schedule callback!\n");
}
}
// Remember that timers_run() must be called periodically elsewhere
// for the callback to actually execute after the delay.
```
## Best Practices
1. **Enable Monotonic Timer:** For accurate timing and stopwatch
functionality, ensure `CONFIG(HAVE_MONOTONIC_TIMER)` is enabled and a
suitable platform timer is configured.
2. **Minimize Stopwatch Overhead:** While lightweight, frequent calls,
especially `timer_monotonic_get()` implicitly called by stopwatch
functions, can add up. Measure larger, significant code blocks rather
than tiny ones in tight loops unless absolutely necessary.
3. **Use Appropriate Time Units:** Choose `usecs` or `msecs` variants
based on the scale of time you are dealing with.
4. **Handle Timeouts Gracefully:** When using expiration or
`wait_ms`/`wait_us`, always check the result and handle the timeout
case appropriately. Don't assume success.
5. **Process Timer Callbacks:** If using `timer_sched_callback`, ensure
`timers_run()` is called regularly in your main processing loops or
idle states.
6. **Avoid `mdelay` for Polling:** Prefer `wait_ms` or manual polling
with `stopwatch_expired` when waiting for conditions, as `mdelay`
offers no timeout handling or feedback.
7. **Consider Platform Accuracy:** Timer resolution and accuracy vary
between platforms. Don't assume microsecond precision unless verified
for the target hardware.
## Limitations
1. **Monotonic Timer Dependence:** Stopwatch and timer callbacks rely
heavily on `CONFIG(HAVE_MONOTONIC_TIMER)`. Without it, their
behavior is limited.
2. **Timer Resolution:** Accuracy is limited by the underlying platform
timer's resolution and the frequency of `timer_monotonic_get()`
updates internally.
3. **64-bit Microsecond Counter:** While large, the
`uint64_t microseconds` counter will eventually wrap around
(after ~584,000 years), though this is not a practical concern for
boot times. More relevant is the potential rollover of the
*underlying hardware counter* between `timer_monotonic_get` calls,
which the implementation must handle correctly (typically ok for
intervals up to several seconds).
4. **Busy Waiting:** `stopwatch_wait_until_expired` and the internal
loops of `wait_us`/`wait_ms` (and potentially the fallback in
`udelay`/`mdelay`) perform busy-waits, consuming CPU cycles. Consider
alternatives like interrupt-driven timers or yielding
(`thread_yield_microseconds`) if power consumption or concurrency is
critical.
5. **Callback Queue Size:** The timer callback queue has a fixed size
defined by `CONFIG(TIMER_QUEUE_SIZE)`, limiting the number of pending
callbacks.
## Troubleshooting
Common issues and solutions:
1. **Inaccurate Timing / Durations are Zero:**
- Verify `CONFIG(HAVE_MONOTONIC_TIMER)` is enabled.
- Check if a platform-specific `init_timer()` is required and being
called.
- Ensure the platform timer frequency is correctly configured.
- Check for potential timer hardware issues or conflicts.
2. **Timeouts Not Working / `wait_ms` Never Returns > 0:**
- Verify the timeout value is appropriate (not too short).
- Double-check the `condition` logic in `wait_ms`/`wait_us`. Is it
actually capable of becoming true?
- Ensure the stopwatch (`sw` or the internal one in `wait_ms`) is
properly initialized before the check loop.
- Confirm `CONFIG(HAVE_MONOTONIC_TIMER)` is enabled.
3. **Timer Callbacks Not Running:**
- Verify `CONFIG(TIMER_QUEUE)` is enabled.
- Ensure `timer_sched_callback()` returned success (0).
- **Crucially:** Check that `timers_run()` is being called
periodically in a suitable loop after the callback was scheduled.
- Make sure the `struct timeout_callback` structure persists in memory
until the callback runs.
4. **Performance Impact:**
- Reduce frequency of stopwatch checks or `wait_ms`/`wait_us` calls if
possible.
- Measure larger code blocks.
- Investigate if the underlying `udelay` implementation is
busy-waiting excessively; yielding (`thread_yield_microseconds`)
might be preferable if available and appropriate.
## Platform-Specific Considerations
The core APIs are generic, but the underlying implementation relies on
platform code:
- **Timer Source:** Platforms implement `timer_monotonic_get` (often
weakly linked) or provide the necessary hooks for it, using hardware
like the APIC timer (x86), Time Base (PPC), architectural timers
(ARM), etc.
- **`init_timer()`:** Platforms may need a custom `init_timer` to set up
clocks, dividers, or enable the timer hardware.
- **`udelay`:** Platforms might provide optimized `udelay`
implementations.
Refer to the documentation and code within specific `src/soc/`,
`src/cpu/`, or `src/arch/` directories for platform details.
## References
- `src/include/timer.h`: Monotonic timer, stopwatch, and callback
declarations.
- `src/include/delay.h`: `udelay`, `mdelay`, `delay` declarations.
- `src/lib/timer.c`: Generic `udelay` (using stopwatch/yield), weak
`init_timer`.
- `src/lib/delay.c`: Generic `mdelay` and `delay` implementations
(calling `udelay`).
- `src/lib/hardwaremain.c`: Example usage of `timers_run()` in boot
state machine.
- Platform timer implementations: Search for `timer_monotonic_get` or
`init_timer` in `src/cpu/`, `src/soc/`, `src/arch/` directories
(e.g., `src/cpu/x86/lapic/apic_timer.c`,
`src/arch/arm64/timer.c`).

View file

@ -1,310 +0,0 @@
# coreboot Threads
## Thread Management
coreboot provides a cooperative threading system that allows for
concurrent execution of tasks during the boot process. The thread API is
particularly useful for implementing asynchronous operations and
managing hardware initialization sequences.
### Thread Creation and Management
#### thread_run
```c
int thread_run(struct thread_handle *handle, enum cb_err (*func)(void *), void *arg)
```
Creates and starts a new thread to execute the specified function.
**Parameters:**
- `handle`: Pointer to a thread handle structure to track thread state
(Note: `struct thread_handle` is an opaque structure used by the API
to manage the thread's state.)
- `func`: Function to execute in the new thread
- `arg`: Argument to pass to the function
**Returns:**
- 0 on success
- < 0 on failure
**Example:**
```c
struct thread_handle th;
enum cb_err thread_func(void *arg) {
// Thread work here
return CB_SUCCESS;
}
if (thread_run(&th, thread_func, NULL) < 0) {
printk(BIOS_ERR, "Failed to create thread\n");
} else {
// Wait for the thread to complete and check its status
enum cb_err err = thread_join(&th);
if (err != CB_SUCCESS) {
printk(BIOS_ERR, "Thread failed with error %d\n", err);
}
}
```
#### thread_run_until
```c
int thread_run_until(struct thread_handle *handle, enum cb_err (*func)(void *), void *arg,
boot_state_t state, boot_state_sequence_t seq)
```
Creates a thread that blocks boot state transitions until completion.
**Parameters:**
- `handle`: Pointer to a thread handle structure
- `func`: Function to execute
- `arg`: Argument to pass to the function
- `state`: Boot state to block
- `seq`: Boot state sequence to block
**Returns:**
- 0 on success
- < 0 on failure
**Example:**
```c
struct thread_handle th;
enum cb_err init_func(void *arg) {
// Hardware initialization
return CB_SUCCESS;
}
// Block BS_DEV_ENABLE until initialization completes
thread_run_until(&th, init_func, NULL, BS_DEV_ENABLE, 0);
```
### Thread Synchronization
#### thread_join
```c
enum cb_err thread_join(struct thread_handle *handle)
```
Waits for a thread to complete and returns its error code.
**Parameters:**
- `handle`: Thread handle to wait for
**Returns:**
- Thread's error code (e.g., `CB_SUCCESS`, `CB_ERR`). See
`src/include/cb_err.h` for details.
**Example:**
```c
struct thread_handle th;
// ... create thread ...
enum cb_err err = thread_join(&th);
if (err != CB_SUCCESS) {
printk(BIOS_ERR, "Thread failed with error %d\n", err);
}
```
### Thread Yielding
Yielding is crucial in a cooperative multitasking system like
coreboot's. Threads must explicitly yield control using `thread_yield`
or `thread_yield_microseconds` to allow other threads to run. Failure to
yield can lead to a single thread monopolizing the CPU, preventing other
tasks from executing.
#### thread_yield
```c
int thread_yield(void)
```
Yields the current thread's execution to allow other threads to run.
**Returns:**
- 0 on success
- < 0 if thread cannot yield
**Example:**
```c
while (!condition) {
if (thread_yield() < 0) {
printk(BIOS_ERR, "Failed to yield thread\n");
break;
}
}
```
#### thread_yield_microseconds
```c
int thread_yield_microseconds(unsigned int microsecs)
```
Yields the current thread for a specified number of microseconds.
**Parameters:**
- `microsecs`: Number of microseconds to yield
**Returns:**
- 0 on success
- < 0 if thread cannot yield
**Example:**
```c
// Wait for 100 microseconds
if (thread_yield_microseconds(100) < 0) {
printk(BIOS_ERR, "Failed to yield thread\n");
}
```
### Thread Cooperation Control
#### thread_coop_enable
```c
void thread_coop_enable(void)
```
Enables cooperative behavior for the current thread.
**Example:**
```c
thread_coop_enable(); // Allow thread to yield
```
#### thread_coop_disable
```c
void thread_coop_disable(void)
```
Disables cooperative behavior for the current thread.
**Example:**
```c
thread_coop_disable(); // Prevent thread from yielding
```
### Thread Mutexes
#### thread_mutex_lock
```c
void thread_mutex_lock(struct thread_mutex *mutex)
```
Acquires a mutex lock, waiting if necessary.
**Parameters:**
- `mutex`: Mutex to lock
**Example:**
```c
struct thread_mutex mtx = THREAD_MUTEX_INITIALIZER; // Or = { .locked = false };
thread_mutex_lock(&mtx);
// Critical section
thread_mutex_unlock(&mtx);
```
#### thread_mutex_unlock
```c
void thread_mutex_unlock(struct thread_mutex *mutex)
```
Releases a mutex lock.
**Parameters:**
- `mutex`: Mutex to unlock
## Best Practices
1. **Thread Safety**:
- Use mutexes to protect shared resources
- Be careful with global variables in threaded code
- Consider thread cooperation when implementing critical sections
2. **Resource Management**:
- Always join threads that you create using `thread_run` to check
their completion status and clean up resources. Threads started
with `thread_run_until` are implicitly managed by the boot state
machine and typically do not require explicit joining.
- Consistently check return values from thread creation and operation
functions (like `thread_run`, `thread_yield`, `thread_join`) to
detect errors early.
- Clean up resources allocated or used within thread functions before
they exit.
3. **Performance Considerations**:
- Use thread_yield_microseconds for precise timing
- Minimize time spent in critical sections
- Consider using thread_run_until for hardware initialization
4. **Error Handling**:
- Check thread creation and operation return values (as noted in
Resource Management).
- Implement proper error handling within thread functions, returning
appropriate `cb_err` values.
- Use `thread_join` (for `thread_run` threads) to check the final
completion status.
## Common Patterns
### Hardware Initialization
```c
struct thread_handle init_th;
enum cb_err init_hardware(void *arg) {
// Initialize hardware
if (hardware_init() != 0)
return CB_ERR;
return CB_SUCCESS;
}
// Run initialization in a thread
thread_run_until(&init_th, init_hardware, NULL, BS_DEV_ENABLE, 0);
```
### Asynchronous Operation
```c
struct thread_handle async_th;
enum cb_err async_operation(void *arg) {
// Perform async operation
while (!operation_complete()) {
if (thread_yield() < 0)
return CB_ERR;
}
return CB_SUCCESS;
}
// Start async operation
thread_run(&async_th, async_operation, NULL);
```
### Critical Section Protection
```c
struct thread_mutex resource_mtx = { .locked = false };
void access_shared_resource(void) {
thread_mutex_lock(&resource_mtx);
// Access shared resource
thread_mutex_unlock(&resource_mtx);
}
```
## Limitations
1. The thread system is cooperative, not preemptive.
2. Threads must explicitly yield to allow other threads to run.
3. Thread operations are typically only available after RAM
initialization (in ramstage and later). Check specific environment
constraints if unsure.
4. Thread count is limited by the `CONFIG_NUM_THREADS` Kconfig option.
5. Thread stack size is fixed by the `CONFIG_STACK_SIZE` Kconfig option.

View file

@ -2,408 +2,175 @@
## Introduction
The aim of the timestamp library is to make it easier for different
boards to save timestamps in cbmem / stash (until cbmem is brought up)
by providing a simple API to initialize, add, and sync timestamps. In
order to make the timestamps persistent and accessible from the kernel,
we need to ensure that all the saved timestamps end up in cbmem under
The aim of the timestamp library is to make it easier for different boards
to save timestamps in cbmem / stash (until cbmem is brought up) by
providing a simple API to initialize, add and sync timestamps. In order
to make the timestamps persistent and accessible from the kernel, we
need to ensure that all the saved timestamps end up in cbmem under
the CBMEM_ID_TIMESTAMP tag. However, until the cbmem area is available,
the timestamps can be saved to a SoC-defined `_timestamp` region if one
is defined in the board's `memlayout.ld`. The work of identifying the
right location for storing timestamps is done by the library and is not
exposed to the user.
Timestamps in coreboot are a critical feature for performance analysis,
debugging, and optimization of the boot process. They provide precise
timing information about various stages and operations during system
initialization, allowing developers to identify bottlenecks and optimize
boot performance. The timestamp system is designed to be lightweight,
accurate, and persistent across different boot stages.
the timestamps can be saved to a SoC-defined \_timestamp region or in a
local stage-specific stash. The work of identifying the right location for
storing timestamps is done by the library and is not exposed to the user.
Working of timestamp library from a user perspective can be outlined in
the following steps:
1. Initialize the base time and reset cbmem timestamp area using
`timestamp_init()`.
2. Start adding timestamps using `timestamp_add()` or
`timestamp_add_now()`.
1. Initialize the base time and reset cbmem timestamp area
2. Start adding timestamps
Behind the scenes, the timestamp library takes care of:
1. Identifying the correct location for storing timestamps (`_timestamp`
region before cbmem is ready, then cbmem region).
2. Add a new cbmem timestamp area based on whether a reset of the cbmem
1. Identifying the correct location for storing timestamps (cbmem or timestamp
region or local stash).
2. Once cbmem is up, ensure that all timestamps are synced from timestamp
region or local stash into the cbmem area.
3. Add a new cbmem timestamp area based on whether a reset of the cbmem
timestamp region is required or not.
3. Once cbmem is ready, ensuring that all timestamps are synced from the
`_timestamp` region into the cbmem area.
Note that if `CONFIG_COLLECT_TIMESTAMPS` is disabled, all timestamp
functions are implemented as no-ops, and no timestamps will be
collected.
### Transition from cache to cbmem
To move timestamps from the cache to cbmem (and initialize the cbmem area in
the first place), we use the CBMEM_INIT_HOOK infrastructure of coreboot.
When cbmem is initialized, the hook is called, which creates the area,
copies all timestamps to cbmem and disables the cache.
After such a transition, timestamp_init() must not be run again.
## Background
The timestamp implementation in coreboot has evolved over time to meet
the needs of the firmware development and performance analysis.
Initially designed as a simple timing mechanism, it has grown into a
sophisticated system that:
- Tracks boot stages and critical operations
- Supports multiple hardware platforms (x86, ARM, RISC-V)
- Provides persistent storage across boot stages
- Enables post-boot analysis of boot performance
- Integrates with vendor-specific firmware components
## Timestamp Architecture
### Transition from cache (`_timestamp` region) to cbmem
To move timestamps from the early `_timestamp` region to cbmem (and
initialize the cbmem area in the first place), we use the
`CBMEM_READY_HOOK` infrastructure of coreboot.
When cbmem is initialized (`cbmem_initialize` or `cbmem_recovery`), the
hook calls the `timestamp_reinit` function. This function allocates or
finds the `CBMEM_ID_TIMESTAMP` area in cbmem, copies all timestamps from
the `_timestamp` region (if used) using `timestamp_sync_cache_to_cbmem`,
and updates an internal global pointer (`glob_ts_table`) to point to the
cbmem table. Subsequent calls to `timestamp_add` will then write
directly to cbmem.
After such a transition, `timestamp_init()` must not be run again (it is
asserted to only run in `ENV_ROMSTAGE_OR_BEFORE`).
### Data structures used
Timestamps are stored using instances of `struct timestamp_table`. A
global pointer, `glob_ts_table`, points to the currently active table,
which is either the `_timestamp` memory region (during early boot) or
the CBMEM area.
The `_timestamp` region acts as an early cache before cbmem is ready.
Its size is determined by `REGION_SIZE(timestamp)` defined in the linker
script (`memlayout.ld`) and dictates the maximum number of entries that
can be stored early on.
For timestamps stored in the cbmem area, a `timestamp_table` is
allocated with space for a fixed number of entries (currently 192)
defined by `MAX_TIMESTAMPS` in `src/lib/timestamp.c`.
## Data structures used
The main structure that maintains information about the timestamp cache is:
```c
struct timestamp_entry {
uint32_t entry_id;
int64_t entry_stamp;
} __packed;
struct __packed timestamp_cache {
uint16_t cache_state;
struct timestamp_table table;
struct timestamp_entry entries[MAX_TIMESTAMP_CACHE];
};
```
>>> _Source: `/src/commonlib/include/commonlib/timestamp_serialized.h`_
### cache_state
The state of the cache is maintained by `cache_state` attribute which can
be any one of the following:
```c
enum {
TIMESTAMP_CACHE_UNINITIALIZED = 0,
TIMESTAMP_CACHE_INITIALIZED,
TIMESTAMP_CACHE_NOT_NEEDED,
};
```
By default, if the cache is stored in local stash (bss area), then
it will be reset to uninitialized state. However, if the cache is
stored in timestamp region, then it might have garbage in any of the
attributes. Thus, if the timestamp region is being used by any board, it is
initialized to default values by the library.
Once the cache is initialized, its state is set to
`CACHE_INITIALIZED`. Henceforth, the calls to cache i.e. `timestamp_add`
know that the state reflected is valid and timestamps can be directly
saved in the cache.
Once the cbmem area is up (i.e. call to `timestamp_sync_cache_to_cbmem`),
we do not need to store the timestamps in local stash / timestamp area
anymore. Thus, the cache state is set to `CACHE_NOT_NEEDED`, which allows
`timestamp_add` to store all timestamps directly into the cbmem area.
### table
This field is represented by a structure which provides overall
information about the entries in the timestamp area:
```c
struct timestamp_table {
uint64_t base_time;
uint16_t max_entries;
uint16_t tick_freq_mhz;
uint32_t num_entries;
struct timestamp_entry entries[]; /* Variable number of entries */
uint64_t base_time;
uint32_t max_entries;
uint32_t num_entries;
struct timestamp_entry entries[0]; /* Variable number of entries */
} __packed;
```
>>> _Source: `/src/commonlib/include/commonlib/timestamp_serialized.h`_
It indicates the base time for all timestamp entries, maximum number
of entries that can be stored, total number of entries that currently
exist and an entry structure to hold variable number of entries.
- `base_time`: Indicates the base time (offset) for all timestamp
entries in this table.
- `max_entries`: Maximum number of entries that can be stored in this
table instance.
- `tick_freq_mhz`: Timestamp tick frequency in MHz. Populated later in
boot.
- `num_entries`: Total number of entries that currently exist in this
table instance.
- `entries`: Array holding the actual timestamp entries.
### entries
This field holds the details of each timestamp entry, up to a maximum
of `MAX_TIMESTAMP_CACHE` which is defined as 16 entries. Each entry is
defined by:
```c
struct timestamp_entry {
uint32_t entry_id;
uint64_t entry_stamp;
} __packed;
```
`entry_id` holds the timestamp id corresponding to this entry and
`entry_stamp` holds the actual timestamp.
### Memory Layout
Timestamps are stored in two locations during the boot process:
1. **`_timestamp` Region**: Used during early boot stages (before CBMEM
is available), *if* defined in `memlayout.ld`.
- Located at the `_timestamp` symbol.
- Persists across stage transitions within `ENV_ROMSTAGE_OR_BEFORE`.
- Size determined by `REGION_SIZE(timestamp)` in the linker script,
which limits the number of entries.
2. **CBMEM**: Used after CBMEM is initialized.
- Identified by `CBMEM_ID_TIMESTAMP`.
- Provides persistent storage across warm reboots.
- Supports a fixed maximum number of entries.
- Automatically synchronized from the `_timestamp` region when CBMEM
becomes available via `timestamp_reinit`.
For timestamps stored in the cbmem area, a `timestamp_table` is allocated
with space for `MAX_TIMESTAMPS` equal to 30. Thus, the cbmem area holds
`base_time`, `max_entries` (which is 30), current number of entries and the
actual entries represented by `timestamp_entry`.
## Function APIs
### Core Functions
### timestamp_init
#### timestamp_init
This function initializes the timestamp cache and should be run as early
as possible. On platforms with SRAM, this might mean in bootblock, on
x86 with its CAR backed memory in romstage, this means romstage before
memory init.
```c
void timestamp_init(uint64_t base);
```
>>> _Source: `/src/include/timestamp.h`_
### timestamp_add
Initializes the timestamp system with a base time. This function sets up
the timestamp cache (`_timestamp` region) and should be run in
bootblock. It must be called once in *one* of the
`ENV_ROMSTAGE_OR_BEFORE` stages. It will fail if no `timestamp` region
is defined in `memlayout.ld`.
Note that platform setup code on x86 or the decompressor on Arm can
measure some timestamps earlier and pass them in to
bootblock_main_with_timestamp().
This function accepts from user a timestamp id and time to record in the
timestamp table. It stores the entry in the appropriate table in cbmem
or `_timestamp` region or local stash.
#### timestamp_add
### timestamp_add_now
```c
void timestamp_add(enum timestamp_id id, int64_t ts_time);
```
>>> _Source: `/src/include/timestamp.h`_
Adds a new timestamp with the specified ID and time value. It stores the
timestamp in the currently active table (either `_timestamp` region or
cbmem). The time value must be an absolute time value (typically
obtained from `timestamp_get()`), as it will be adjusted by subtracting
the table's `base_time` before being stored as an entry.
#### timestamp_add_now
```c
void timestamp_add_now(enum timestamp_id id);
```
>>> _Source: `/src/include/timestamp.h`_
Adds a new timestamp with the current time. This function calls
`timestamp_add` with user-provided id and current time obtained from
`timestamp_get()`.
#### timestamp_rescale_table
```c
void timestamp_rescale_table(uint16_t N, uint16_t M);
```
>>> _Source: `/src/include/timestamp.h`_
Applies a scaling factor N/M to all recorded timestamps (including the
`base_time`).
#### get_us_since_boot
```c
uint32_t get_us_since_boot(void);
```
>>> _Source: `/src/include/timestamp.h`_
Returns the time since boot (relative to `base_time`) in microseconds.
Requires `tick_freq_mhz` to be populated.
#### timestamp_get
```c
uint64_t timestamp_get(void);
```
>>> _Source: `/src/include/timestamp.h`_
Returns the current raw timestamp value from the underlying hardware
timer (platform-specific weak implementation).
#### timestamp_tick_freq_mhz
```c
int timestamp_tick_freq_mhz(void);
```
>>> _Source: `/src/include/timestamp.h`_
Returns the timestamp tick frequency in MHz (platform-specific weak
implementation).
### Timestamp IDs
The system uses predefined timestamp IDs to mark various boot stages and
operations. These are organized in ranges:
- 1-500: Miscellaneous coreboot operations (e.g., `TS_POSTCAR_START`,
`TS_DELAY_START`, `TS_READ_UCODE_START`)
- 500-600: Google/ChromeOS specific (e.g., `TS_VBOOT_START`,
`TS_EC_SYNC_START`).
Note many of the existing timestamps here are no longer
Google-specific since many features originally added for Google
vendorcode have since been migrated into general coreboot code.
- 900-940: AMD specific (e.g., `TS_AGESA_INIT_EARLY_START`)
- 940-950: Intel ME specific (e.g., `TS_ME_INFORM_DRAM_START`)
- 950-989: Intel FSP specific (e.g., `TS_FSP_MEMORY_INIT_START`)
- 990-999: Intel ME specific (continued) (e.g., `TS_ME_ROM_START`)
- 1000+: Payload specific
- Depthcharge: 1000-1199
- ChromeOS Hypervisor: 1200-1299
Refer to `src/commonlib/include/commonlib/timestamp_serialized.h` for
the complete list and descriptions.
This function calls `timestamp_add` with user-provided id and current time.
## Use / Test Cases
The following cases describe the behavior based on the presence of the
`timestamp` region and when cbmem is initialized.
The following cases have been considered while designing the timestamp
library. It is important to ensure that any changes made to this library satisfy
each of the following use cases:
### Case 1: Timestamp Region Exists (Fresh Boot / Resume)
### Case 1: Timestamp Region Exists
In this case, the library needs to call `timestamp_init` as early as possible to
enable the timestamp cache. Once cbmem is available, the values will be
transferred automatically.
This is the standard configuration for collecting early timestamps.
`timestamp_init` must be called in an `ENV_ROMSTAGE_OR_BEFORE` stage to
initialize the `_timestamp` region. When the `CBMEM_READY_HOOK` runs
`timestamp_reinit`, the contents of the `_timestamp` region are copied
to the cbmem table, and subsequent timestamps go directly to cbmem. The
cbmem table is reset on fresh boot or resume.
All regions are automatically reset on initialization.
### Case 2: No timestamp region, fresh boot, cbmem_initialize called after timestamp_init
### Case 2: No Timestamp Region Defined
`timestamp_init` will set up a local cache. cbmem must be initialized before that
cache vanishes - as happens when jumping to the next stage.
If no `timestamp` region is defined in `memlayout.ld`, attempts to call
`timestamp_init` will fail (specifically, `timestamp_cache_get()` will
return NULL). No timestamps can be collected before cbmem is ready.
Timestamps added after `timestamp_reinit` has run (via the
`CBMEM_READY_HOOK`) will be added directly to the cbmem table, but there
will be no `base_time` established from early boot.
### Case 3: No timestamp region, fresh boot, cbmem_initialize called before timestamp_init
This case is not supported right now, just don't call `timestamp_init` after
`cbmem_initialize`. (Patches to make this more robust are welcome.)
### Case 3: Resume
### Case 4: No timestamp region, resume, cbmem_initialize called after timestamp_init
On resume (e.g., x86 S3), `timestamp_reinit` is typically called again.
If `ENV_CREATES_CBMEM` is true for the resume path (as it is for x86
S3), a new cbmem table is allocated by `timestamp_alloc_cbmem_table`,
effectively clearing any pre-suspend timestamps. The `_timestamp` region
content (if any) is copied over, but this usually contains stale data
from the previous boot's early stages.
We always reset the cbmem region before using it, so pre-suspend timestamps
will be gone.
### Case 5: No timestamp region, resume, cbmem_initialize called before timestamp_init
## Configuration
### Kconfig Options
- `CONFIG_COLLECT_TIMESTAMPS`: Enable/disable timestamp collection
globally. If disabled, timestamp functions become no-ops.
- `CONFIG_TIMESTAMPS_ON_CONSOLE`: Print timestamps to console during
boot as they are added.
### Memory Layout
Collecting timestamps before cbmem is ready requires an `_timestamp`
region in the memory layout, defined in the `memlayout.ld` linker
script. Depending on the platform, the memory layout can be for the
board, the SOC, or the Architecture. Any of them will typically follow
the following pattern:
```text
#include <memlayout.h>
...
TIMESTAMP(., 0x200)
...
```
The size allocated to this region determines the maximum number of
timestamps that can be stored before cbmem is available.
The cbmem timestamp table (`CBMEM_ID_TIMESTAMP`) has a fixed size,
currently allowing up to 192 entries. This limit is defined by
`MAX_TIMESTAMPS` in `src/lib/timestamp.c`.
### Hardware Considerations
- x86: `timestamp_init` must be called before CAR (Cache-as-RAM) is torn
down if called from bootblock or separate romstage. The library
includes checks (`timestamp_should_run`) to ensure timestamps are only
added by the primary processor during early boot on AP systems.
- ARM: No special considerations noted in the code.
- RISC-V: No special considerations noted in the code.
## Examples
### Initializing Timestamps (in bootblock)
```c
/* In src/mainboard/$(MAINBOARDDIR)/bootblock.c */
#include <timestamp.h>
#include <timer.h> /* For timestamp_get() default implementation */
void bootblock_mainboard_init(void)
{
/* Initialize timestamp region with current time as base. */
timestamp_init(timestamp_get());
/* Add first timestamp */
timestamp_add_now(TS_BOOTBLOCK_START);
/* ... other bootblock code ... */
}
```
Note: `timestamp_get()` here provides the initial base time. Requires
`CONFIG_COLLECT_TIMESTAMPS=y` and a `timestamp` region.
### Adding Custom Timestamps
```c
#include <timestamp.h>
void my_custom_function(void)
{
timestamp_add_now(TS_DEVICE_INITIALIZE); /* Use a relevant ID */
// ... perform initialization ...
timestamp_add_now(TS_DEVICE_DONE); /* Use a relevant ID */
}
```
## Best Practices
1. **Initialization**:
- Enable `CONFIG_COLLECT_TIMESTAMPS` if needed.
- Define a `timestamp` region in `memlayout.ld` if early
timestamps (before cbmem) are required. Ensure it's large enough
for the expected number of early entries.
- Call `timestamp_init()` exactly once in the earliest possible
`ENV_ROMSTAGE_OR_BEFORE` stage (e.g., `bootblock`).
- Use a consistent base time, typically `timestamp_get()`.
2. **Adding Timestamps**:
- Use appropriate predefined timestamp IDs from
`timestamp_serialized.h` whenever possible. Add custom IDs if
necessary, avoiding conflicts.
- Add timestamps for significant operations or stage transitions
using `timestamp_add_now()`.
- Be mindful of the entry limits: the size of the `_timestamp`
region for early timestamps, and the fixed limit for the cbmem
table. Check for "Timestamp table full" errors in the log.
3. **Analysis**:
- Use the `cbmem -t` utility in the OS (if using LinuxBoot/NERF)
to read and display timestamps stored in CBMEM.
- Consider the `tick_freq_mhz` (also available in the `cbmem -t`
output) when converting raw timestamp differences (`entry_stamp`)
to time units. The raw values are offsets from `base_time`.
We always reset the cbmem region before using it, so pre-suspend timestamps
will be gone.

View file

@ -122,8 +122,10 @@ $ sudo flashrom \
-w coreboot.rom
```
```{eval-rst}
In addition to the information here, please see the
<project:../../tutorial/flashing_firmware/index.md>.
:doc:`../../tutorial/flashing_firmware/index`.
```
### External flashing

View file

@ -130,5 +130,5 @@ facing towards the bottom of the board.
[ASRock H110M-DVS]: https://www.asrock.com/mb/Intel/H110M-DVS%20R2.0/
[MX25L6473E]: http://www.macronix.com/Lists/Datasheet/Attachments/7380/MX25L6473E,%203V,%2064Mb,%20v1.4.pdf
[flashrom]: https://flashrom.org/
[flashrom]: https://flashrom.org/Flashrom
[H110M-DVS manual]: https://web.archive.org/web/20191023230631/http://asrock.pc.cdn.bitgravity.com/Manual/H110M-DVS%20R2.0.pdf

View file

@ -115,8 +115,10 @@ $ sudo flashrom --noverify-all --ifd -i bios -p internal -w coreboot.rom
The use of `--noverify-all` is required since the Management Engine
region is not readable even by the host.
```{eval-rst}
In addition to the information here, please see the
<project:../../tutorial/flashing_firmware/index.md>.
:doc:`../../tutorial/flashing_firmware/index`.
```
## Hardware monitoring and fan control

View file

@ -4,7 +4,9 @@ This page describes how to run coreboot on the [ASRock H81M-HDS].
## Required proprietary blobs
Please see <project:../../northbridge/intel/haswell/mrc.bin.md>.
```{eval-rst}
Please see :doc:`../../northbridge/intel/haswell/mrc.bin`.
```
## Building coreboot
@ -73,8 +75,9 @@ facing towards the bottom of the board.
in coreboot. The `coretemp` driver can still be used for accurate CPU
temperature readings from an OS.
Please also see
<project:../../northbridge/intel/haswell/known-issues.md>.
```{eval-rst}
Please also see :doc:`../../northbridge/intel/haswell/known-issues`.
```
## Untested
@ -126,5 +129,5 @@ Please also see
[ASRock H81M-HDS]: https://www.asrock.com/mb/Intel/H81M-HDS/
[W25Q32FV]: https://www.winbond.com/resource-files/w25q32fv%20revi%2010202015.pdf
[flashrom]: https://flashrom.org/
[flashrom]: https://flashrom.org/Flashrom
[Board manual]: https://web.archive.org/web/20191231093418/http://asrock.pc.cdn.bitgravity.com/Manual/H81M-HDS.pdf

View file

@ -5,24 +5,24 @@ This page describes how to run coreboot on the [ASRock IMB-1222].
## Technology
```{eval-rst}
+---------+---------------------------------------------------------------+
| CPU | | Intel 10th Gen (Comet lake-S) Core Processors (LGA-1200) |
| | | CPUs over 80W will be limited due to power design |
+---------+---------------------------------------------------------------+
| DRAM | 2 SO-DIMM slots, DDR4 2933/2666/2400 MHz |
+---------+---------------------------------------------------------------+
| Chipset | Intel Q470E |
+---------+---------------------------------------------------------------+
| SuperIO | Fintek F81966 |
+---------+---------------------------------------------------------------+
| TPM | Infineon SLB 9670VQ2.0 |
+---------+---------------------------------------------------------------+
| Boot | USB, SATA, NVMe |
+---------+---------------------------------------------------------------+
| Power | | Laptop Power Supply: |
| | | - 12V DC-in (IMB-1222) |
| | | - 12V~28V DC-in (IMB-1222-WV) |
+---------+---------------------------------------------------------------+
+------------+---------------------------------------------------------------+
| CPU | Intel 10th Gen (Comet lake-S) Core Processors (LGA-1200) |
| | CPUs over 80W will be limited due to power design |
+------------+---------------------------------------------------------------+
| DRAM | 2 SO-DIMM slots, DDR4 2933/2666/2400 MHz |
+------------+---------------------------------------------------------------+
| Chipset | Intel Q470E |
+------------+---------------------------------------------------------------+
| Super I/O | Fintek F81966 |
+------------+---------------------------------------------------------------+
| TPM | Infineon SLB 9670VQ2.0 |
+------------+---------------------------------------------------------------+
| Boot | USB, SATA, NVMe |
+------------+---------------------------------------------------------------+
| Power | Laptop Power Supply: |
| | - 12V DC-in (IMB-1222) |
| | - 12V~28V DC-in (IMB-1222-WV) |
+------------+---------------------------------------------------------------+
```
```text
@ -70,7 +70,7 @@ This page describes how to run coreboot on the [ASRock IMB-1222].
| ALC122 | | LPC
+--------------+ +--------------+
+-----------------------+ +--------------+ | | +------------+
| 2 x COM RS232/422/485 |---| ST3243E |---| Fintek |----| CPU FAN x1 |
| 2 x COM RS232/422/482 |---| ST3243E |---| Fintek |----| CPU FAN x1 |
+-----------------------+ +--------------+ | F81966 | +------------+
+-----------------------+ +--------------+ | SuperIO | +------------+
| 2 x COM RS232 |---| ST3243E |---| |----| NCT 3941SA |
@ -85,48 +85,6 @@ This page describes how to run coreboot on the [ASRock IMB-1222].
This port was created without a schematic/boardview, reverse engineering only.
Feel free to make changes.
## Required proprietary blobs
To build full working image of coreboot, the following blobs are required:
```{eval-rst}
+-----------------+-------------------------------------------+-------------------------+
| Binary file | Apply | Required/Optional |
+=================+===========================================+=========================+
| FSP-M & FSP-S | | Intel Firmware Support Package 2.1 | Required |
| | | 10th Generation Intel® Core™ processors | |
| | | and chipsets (formerly Comet Lake) | |
+-----------------+-------------------------------------------+-------------------------+
| IFD | Intel Flash Descriptor | Required |
+-----------------+-------------------------------------------+-------------------------+
| ME | Intel Management Engine | Required |
+-----------------+-------------------------------------------+-------------------------+
| GBE | Gigabit Ethernet Configuration | | Optional |
| | | | (if LAN2 is enabled) |
+-----------------+-------------------------------------------+-------------------------+
```
### FSP
Intel company provides [Firmware Support Package (2.1)](../../soc/intel/fsp/index.md)
to initialize this generation silicon. Please see this
[document](../../soc/intel/code_development_model/code_development_model.md).
### IFD, ME, GBE
Use the [vendor's firmware] version 1.80 to extract the IFD, ME, GBE blobs from it, according to
the [Intel IFD Binary Extraction Tutorial](../../util/ifdtool/binary_extraction.md).
```bash
wget --tries=5 "https://web.archive.org/web/20250413105432/https://download.asrock.com/IPC/BIOS/IMB-1222(1.80)ROM.zip"
unzip "IMB-1222(1.80)ROM.zip"
ifdtool --platform cnl -x IM12221.80
File IM12221.80 is 33554432 bytes
flashregion_0_flashdescriptor.bin Flash Region 0 (Flash Descriptor): 00000000 - 00000fff
flashregion_2_intel_me.bin Flash Region 2 (Intel ME): 00003000 - 01002fff
flashregion_3_gbe.bin Flash Region 3 (GbE): 00001000 - 00002fff
```
## Building coreboot
The following commands will help quickly configure and build a project for this board:
@ -152,8 +110,6 @@ make
+---------------+------+---------+-----------+
| Windows 10 | V | | |
+---------------+------+---------+-----------+
| Windows 11 | V | | |
+---------------+------+---------+-----------+
| Android 13 | | V | |
+---------------+------+---------+-----------+
```
@ -162,12 +118,9 @@ make
- SeaBIOS (1.16.3);
- edk2 [MrChromebox fork] (uefipayload_2408).
### Additional information
- Ubuntu 22.04 (Linux 6.5.0-15-generic);
- Ubuntu 24.04 (Linux 6.8.0-41-generic);
- Microsoft Windows 10 Pro (10.0.19045.4780, 22H2 2022);
- Microsoft Windows 11 Pro (10.0.26100.3194, 24H2 2024);
- Andoid 13, [Bliss OS] x86_64 (16.9.7, Linux 6.1.112-gloria-xanmod1).
## Flashing coreboot
@ -178,8 +131,8 @@ make
+=====================+==========================+
| Socketed flash | yes |
+---------------------+--------------------------+
| Model | | W25Q256JV |
| | | MX25L25673G |
| Model | W25Q256JV |
| | MX25L25673G |
+---------------------+--------------------------+
| Size | 32 MiB |
+---------------------+--------------------------+
@ -218,7 +171,7 @@ information about this [here](../../tutorial/flashing_firmware/index.md).
- USB 2.0 ports;
- USB 3.2 ports;
- M.2 Key-E 2230 slot for Wireless (PCIe x1, USB 2.0 and CNVi);
- M.2 Key-B 3042/3052 WWAN slot for 4G/5G modem (PCIe x1, USB 3.0);
- M.2 Key-B 3042/3052 slot for 4G/5G modem (PCIe x1);
- M.2 Key-M 2242/2260/2280 for SSD/NVMe (PCIE x4, SATA3);
- LAN1 Intel I225LM/I225V, 10/100/1000/2500 Mbps;
- LAN2 Intel I219LM, 10/100/1000 Mbps;
@ -232,14 +185,14 @@ information about this [here](../../tutorial/flashing_firmware/index.md).
## Unknown/untested
- USB 3.0 in M.2 Key-B 3042/3052 slot (currently disabled);
- eDP/LVDS (currently disabled);
- PCIe riser cards;
- SPDIF;
- SATA RAID.
[ASRock IMB-1222]: https://web.archive.org/web/20220924171403/https://www.asrockind.com/en-gb/IMB-1222
[vendor's firmware]: https://web.archive.org/web/20250413105432/https://download.asrock.com/IPC/BIOS/IMB-1222(1.80)ROM.zip
[flashrom]: https://flashrom.org/
[flashrom]: https://flashrom.org/Flashrom
[MrChromebox fork]: https://github.com/MrChromebox/edk2
[XutaxKamay fork]: https://github.com/XutaxKamay/me_cleaner
[Bliss OS]: https://blissos.org/

View file

@ -162,7 +162,7 @@ Tested even with/without the Bolton and Hudson blobs.
[ASUS A88XM-E]: https://www.asus.com/Motherboards/A88XME/
[Board manual]: https://dlcdnets.asus.com/pub/ASUS/mb/SocketFM2/A88XM-E/E9125_A88XM-E.pdf
[flashrom]: https://flashrom.org/
[flashrom]: https://flashrom.org/Flashrom
[GD25Q64]: http://www.elm-tech.com/ja/products/spi-flash-memory/gd25q64/gd25q64.pdf
[Piledriver]: https://en.wikipedia.org/wiki/Piledriver_%28microarchitecture%29#APU_lines
[Sea Islands]: https://en.wikipedia.org/wiki/Graphics_Core_Next#GCN_2nd_generation

View file

@ -192,7 +192,7 @@ This version is usable for all the GPUs.
[ASUS F2A85-M]: https://web.archive.org/web/20160320065008/http://www.asus.com/Motherboards/F2A85M/
[Board manual]: https://web.archive.org/web/20211028063105/https://dlcdnets.asus.com/pub/ASUS/mb/SocketFM2/F2A85-M/E8005_F2A85-M.pdf
[flashrom]: https://flashrom.org/
[flashrom]: https://flashrom.org/Flashrom
[Piledriver]: https://en.wikipedia.org/wiki/Piledriver_%28microarchitecture%29#APU_lines
[TeraScale 3]: https://en.wikipedia.org/wiki/TeraScale_%28microarchitecture%29#TeraScale_3
[W25Q64FV]: https://web.archive.org/web/20220127184640/https://www.winbond.com/resource-files/w25q64fv%20revs%2007182017.pdf

View file

@ -1,49 +0,0 @@
# ASUS PRIME H610i-PLUS
This is a Mini-ITX LGA1700 (Alder Lake/Raptor Lake) motherboard, using the H610 chipset and
DDR4 RAM. It's a close relative of the H610M-K, and like it is also sold in DDR4 and DDR5
variants.
## Variants
- *ASUS PRIME H610i-PLUS **D4***: uses DDR4 RAM, supported
- *ASUS PRIME H610i-PLUS* (no "D4"): uses DDR5 RAM, not currently supported by this port
## Flashing
This mainboard uses a standard 3.3V SOIC-8 SPI flash chip. The vendor firmware enables write
protection, thus for initial installation an external programmer is required. Thereafter,
coreboot can be updated internally using `flashrom -p internal`.
An external programmer can be connected using an ordinary chip clip, but for development or
testing, it can be more convenient to flash via the TPM header. A pinout can be found on Page
1-4 of the board's User's Manual - to select the flash chip, connect your CS line to
F_SPI_CS0#_R. An adapter cable can be made using a 2x7-pin 2.0mm female header, or a set of
2.0mm jumper wires. Beware, despite its similar appearance, this TPM header pinout is NOT
compatible with the pinout found on the MSI Z690A and Z790P boards (adapters for flashing those
boards over the SPI TPM header will not work on ASUS boards).
## Feature Support
### Working:
- Console over onboard serial port
- PS/2 keyboard
- Port 80 POST codes over ASUS debug header
- All USB ports, including USB3 working, except front USB2
- All outputs (DP, HDMI, VGA) for iGPU
- M.2 slot
- PCIe WiFi card in WiFi slot
- Onboard Ethernet
- PCIe ASPM and clock power management for all devices
- x16 PCIe slot
- All SATA ports
- Hard drive indicator LED
- All audio including front panel
- Fan control
- ME disable with HAP bit in IFD
- HSPHY-in-FMAP when ME is disabled
### Untested:
- CNVi WiFi card in WiFi slot
- SPI TPM
- Front USB2 ports (did not have an adapter on hand to test)
- Status LEDs in actual error states (they do show a normal status normally)
### Not working:
- S3 sleep

View file

@ -105,4 +105,4 @@ for only CPU models that the board will actually be run with.
## Extra resources
[flashrom]: https://flashrom.org/
[flashrom]: https://flashrom.org/Flashrom

View file

@ -103,4 +103,4 @@ for only CPU models that the board will actually be run with.
## Extra resources
[flashrom]: https://flashrom.org/
[flashrom]: https://flashrom.org/Flashrom

View file

@ -91,4 +91,4 @@ flash externally.
[ASUS P8C WS]: https://www.asus.com/supportonly/p8c_ws/helpdesk_knowledge/
[W25Q64FVA1Q]: https://www.winbond.com/resource-files/w25q64fv%20revs%2007182017.pdf
[flashrom]: https://flashrom.org/
[flashrom]: https://flashrom.org/Flashrom

View file

@ -107,5 +107,5 @@ region is not readable even by the host.
[ASUS P8H61-M LX]: https://www.asus.com/Motherboards/P8H61M_LX/
[W25Q32BV]: https://web.archive.org/web/20211002141814/https://www.winbond.com/resource-files/w25q32bv_revi_100413_wo_automotive.pdf
[flashrom]: https://flashrom.org/
[flashrom]: https://flashrom.org/Flashrom
[Board manual]: http://dlcdnet.asus.com/pub/ASUS/mb/LGA1155/P8H61_M_LX/E6803_P8H61-M_LX.zip

View file

@ -100,4 +100,4 @@ region is not readable even by the host.
[ASUS P8H61-M Pro]: https://www.asus.com/Motherboards/P8H61M_Pro/
[W25Q32BV]: https://www.winbond.com/resource-files/w25q32bv_revi_100413_wo_automotive.pdf
[flashrom]: https://flashrom.org/
[flashrom]: https://flashrom.org/Flashrom

View file

@ -78,4 +78,4 @@ work. The flash chip is socketed, so it's easy to remove and reflash.
[ASUS P8H77-V]: https://www.asus.com/supportonly/p8h77v/helpdesk_knowledge/
[W25Q64FVA1Q]: https://www.winbond.com/resource-files/w25q64fv%20revs%2007182017.pdf
[flashrom]: https://flashrom.org/
[flashrom]: https://flashrom.org/Flashrom

View file

@ -169,4 +169,4 @@ The board has two onboard buttons, each with a related LED nearby.
[ASUS P8Z77-M]: https://www.asus.com/supportonly/p8z77-m/helpdesk_manual/
[W25Q64FVA1Q]: https://www.winbond.com/resource-files/w25q64fv%20revs%2007182017.pdf
[flashrom]: https://flashrom.org/
[flashrom]: https://flashrom.org/Flashrom

View file

@ -165,4 +165,4 @@ easy to remove and reflash.
[ASUS P8Z77-M PRO]: https://www.asus.com/Motherboards/P8Z77M_PRO/
[W25Q64FVA1Q]: https://www.winbond.com/resource-files/w25q64fv%20revs%2007182017.pdf
[flashrom]: https://flashrom.org/
[flashrom]: https://flashrom.org/Flashrom

View file

@ -108,5 +108,5 @@ See [Asus Wi-Fi Go! v1].
[ASUS P8Z77-V]: https://www.asus.com/supportonly/p8z77v/helpdesk_knowledge/
[W25Q64FVA1Q]: https://www.winbond.com/resource-files/w25q64fv%20revs%2007182017.pdf
[flashrom]: https://flashrom.org/
[flashrom]: https://flashrom.org/Flashrom
[Asus Wi-Fi Go! v1]: ./wifigo_v1.md

View file

@ -1,258 +0,0 @@
# ASUS P8Z77-V LE PLUS
This page describes how to run coreboot on the [ASUS P8Z77-V LE PLUS].
## Flashing coreboot
```{eval-rst}
+---------------------+----------------+
| Type | Value |
+=====================+================+
| Socketed flash | yes |
+---------------------+----------------+
| Model | W25Q64FVA1Q |
+---------------------+----------------+
| Size | 8 MiB |
+---------------------+----------------+
| Package | DIP-8 |
+---------------------+----------------+
| Write protection | yes |
+---------------------+----------------+
| Dual BIOS feature | no |
+---------------------+----------------+
| Internal flashing | yes |
+---------------------+----------------+
```
### How to flash
The main SPI flash cannot be written because the vendor firmware disables BIOSWE
and enables BLE/SMM_BWP flags in BIOS_CNTL for their latest BIOSes. An external
programmer is required. You must flash standalone, flashing in-circuit doesn't
work. The flash chip is socketed, so it's easy to remove and reflash.
See page 2-2 of user's manual for flash chip location.
### Extra preparations for changing PCIe slot configuration
On vendor firmware, the black PCIEX16_3 slot can be configured as x2 or x4.
If set for x4, PCIEX1_1 and PCIEX1_2 are disabled.
Before flashing coreboot for the first time, decide how you want to use the PCIe slots.
If you want to be able to choose between using the two PCIEX1 slots and the PCIEX16_3 slot at
x4 bandwidth, you need to do some preparation, namely make two backups of the whole flash
chip, specifically the flash descriptor under both configurations.
Enter vendor UEFI setup and check the PCIEX16_3 (black) slot bandwidth setting. You'll back up
under this setting first. Once one backup is made, come back and change the setting
from x2 to x4 (or vice versa) and reboot once, then make the other backup.
With PCIEX16_3 (black) slot bandwidth at x2, run these commands:
```bash
flashrom -p internal -r pciex163_x2.bin
dd if=pciex163_x2.bin of=ifd-pciex163_x2.bin bs=4096 count=1
```
With PCIEX16_3 (black) slot bandwidth at x4, run these commands:
```bash
flashrom -p internal -r pciex163_x4.bin
dd if=pciex163_x4.bin of=ifd-pciex163_x4.bin bs=4096 count=1
```
(`dd` needs not be run as root.)
Save the shortened `ifd-pciex163_*.bin` files for when you want to change the configuration.
Keep one of the full backups as well.
See "PCIe config" section below for more details.
## Working
- Core i5-3570K and i7-3770K CPUs
- Corsair CMZ16GX3M2A1600C10 2x8GB memory kit
- SeaBIOS 1.16.3
- edk2 mrchromebox fork uefipayload_2501
- Kernel 6.12.7
- All USB2 ports (mouse, keyboard)
- All USB3 ports
- Z77 SATA ports (WD Blue SA510, Liteon LH-20A1L)
- nVidia 8800GT GPU in PCIEX16_1 slot running x16
- PCI slots (Sound Blaster Live! Value)
- RTL8111F LAN
- CPU temperature sensors and hardware monitor
(see [below](#hardware-monitoring-and-fan-speed-control))
- Integrated graphics with libgfxinit and VBT
(all ports tested and working)
- Both PCIe x1 slots when properly configured
(see [How to flash](#how-to-flash) above and [PCIe config](#pcie-config);
Atheros 928x miniPCIe Wifi on adapter & MSI Herald-BE Wifi7 adapter)
- PCIe x4 slot with Intel Octane H10 1TB NVMe at x2 mode
- Serial port
- PS/2 keyboard
- Analog 7.1 audio out the 3.5mm jacks on rear panel
- Front HDA audio panel
- Digital audio out (Optical, internal SPDIF header, HDMI, DisplayPort)
Although a `spdif_dest` option is provided for feature parity with vendor firmware,
it doesn't seem to matter and digital audio out is available through all ports.
It does, however, change how the ports are presented to the OS.
- S3 suspend from Linux
## Known issues
- For 7.1 analog audio to work, at least the front channel (green jack) must be connected.
## Untested
- Hotplug of Z77 SATA ports
- EHCI debugging
## Not working
- Wake-on-LAN
- PS/2 mouse (requires a patch currently under review)
- Asmedia USB 3.0 battery charging support (for USB 3 ports on the LAN stack)
- USB Charger+ (When the bottom USB 3 port on the eSATA stack, also used for BIOS flashback,
remains powered while the rest of the system is off. Both features are controlled by the same
AI1314 controller.)
- Marvell SATA ports are brought up in IDE mode, pata_marvell driver is loaded,
but are effectively unusable.
## PCIe config
See [Extra preparations](#extra-preparations-for-changing-pcie-slot-configuration) section above.
Changing the PCIe slot configuration requires manipulating a PCH GPIO line and a soft strap in
the flash chip's descriptor section, which is read-only at runtime. coreboot programs the GPIO
to match the soft strap, but how it can update the soft strap itself is to be determined. Until
then, to make this change you have to re-flash the descriptor yourself, with one of the two
copies you previously saved per above:
```bash
flashrom -p internal --ifd -i fd -w ifd-pciex163_x2.bin
```
## Hardware monitoring and fan speed control
Although all fan ports are 4-pin for PWM fans, only CPU_FAN has actual PWM control;
all other fan speed control is by voltage only.
Write 1 into `/sys/class/hwmon/hwmon1/pwm1_mode` to enable CHA_FAN1 control, otherwise it
runs at full speed.
`fan5`/`pwm5` is not implemented and should be ignored.
These are the sensors.conf settings for this board:
```
label fan1 "CHA_FAN1"
label fan2 "CPU_FAN"
label fan3 "CHA_FAN2"
label fan4 "CHA_FAN3"
ignore fan5
label in1 "+12V"
label in4 "+5V"
compute in1 @*12, @/12
compute in4 @*5, @/5
set temp1_type 4
set temp2_type 4
```
## Extra onboard switches and LEDs
- `BIOS_FLBK`:
Vendor firmware uses this button to facilitate a simple update mechanism
via a USB drive plugged into the bottom USB port of the USB/ESATA6G stack.
It connects to the proprietary AI1314 controller, along with `FLBK_LED`.
- `MemOK!`:
OEM firmware uses this button for memory tuning related to overclocking.
It connects to pin 74 of super I/O.
- `DRAM_LED` lights up when there is a memory problem or when vendor MemOK! feature is
operating. Connects to GP07 line of super I/O. coreboot lights it up during memory init
similar to vendor firmware.
- `EPU`: When enabled, lights up `EPU_LED` and takes PCH GPIO44 low.
- `TPU`: When enabled, lights up `TPU_LED` and takes PCH GPIO45 low.
`EPU` and `TPU` are cues to vendor firmware to enable two embedded controllers for
overclocking features. coreboot is not yet able to make use of these two signals.
- `SB_PWR` lights up whenever board is receiving power. It's all hardware
and does not concern coreboot.
- `DRCT` is an undocumented 2-pin header next to the front panel connector block. It
connects to both the power button circuit and Z77's intruder detection input. Shorting this
header triggers both. With coreboot it currently works the same as the power button.
## Extra exposed GPIOs at `TB_HEADER`
A number of GPIO lines are broken out to `TB_HEADER` to support the ThunderboltEX adapter,
which never took off. Now they're yours to play with. Additional programming may be required such
as enabling GPIO by I/O for maximum effect.
This may be safely ignored for most normal uses.
**Be careful not to apply more than 3.3v to these pins!** And do not touch the two pins
labeled "NOT A GPIO".
Pinout:
```
+---+---+---+---+---+
| 2 | 4 | 5 | 7 | 9 |
+---+---+---+---+---+
| 1 | 3 | | 6 | 8 |
+---+---+---+---+---+
```
```{eval-rst}
+-----+-----------------------+----------+--------+
| Pin | Name | Source | GPIO # |
+=====+=======================+==========+========+
| 1 | S_DP_DDC_CLK_TO_TB | **NOT A GPIO** |
+-----+-----------------------+----------+--------+
| 2 | TB_GPIO_6 | NCT6779D | 14 |
+-----+-----------------------+----------+--------+
| 3 | S_DP_DDC_DATA_TO_TB | **NOT A GPIO** |
+-----+-----------------------+----------+--------+
| 4 | TB_GPIO_7 | NCT6779D | 13 |
+-----+-----------------------+----------+--------+
| 5 | TB_FWUPDATE | NCT6779D | 11 |
+-----+-----------------------+----------+--------+
| 6 | TB_DEV_HPD | Z77 | 0 |
+-----+-----------------------+----------+--------+
| 7 | TB_GO2SX | NCT6779D | 17 |
+-----+-----------------------+----------+--------+
| 8 | TB_GO2SX#_ACK | NCT6779D | 16 |
+-----+-----------------------+----------+--------+
| 9 | Not connected |
+-----+-------------------------------------------+
```
Pins 2, 4, 6, 8 have 1M ohm pulldowns.
## Technology
```{eval-rst}
+------------------+--------------------------------------------------+
| Northbridge | :doc:`../../northbridge/intel/sandybridge/index` |
+------------------+--------------------------------------------------+
| Southbridge | bd82x6x |
+------------------+--------------------------------------------------+
| CPU | model_206ax |
+------------------+--------------------------------------------------+
| Super I/O | Nuvoton NCT6779D |
+------------------+--------------------------------------------------+
| EC | TPU (ENE KB3722), AI1314 |
+------------------+--------------------------------------------------+
| Coprocessor | Intel Management Engine |
+------------------+--------------------------------------------------+
```
## Extra resources
- [Flash chip datasheet][W25Q64FVA1Q]
[ASUS P8Z77-V LE PLUS]: https://www.asus.com/supportonly/p8z77-v%20le%20plus/helpdesk_manual/
[W25Q64FVA1Q]: https://www.winbond.com/resource-files/w25q64fv%20revs%2007182017.pdf
[flashrom]: https://flashrom.org/
[rtnicpg]: https://github.com/redchenjs/rtnicpg

View file

@ -142,6 +142,6 @@ the cables or not being populated on the board case.
- Intruder detection
- Wake-on-Lan from ACPI S3
[flashrom]: https://flashrom.org/
[flashrom]: https://flashrom.org/Flashrom
[Dell OptiPlex 9010 specifications]: https://www.dell.com/downloads/global/products/optix/en/dell_optiplex_9010_spec_sheet.pdf
[UEFITool]: https://github.com/LongSoft/UEFITool

View file

@ -20,23 +20,29 @@ To build full working image of coreboot, the following blobs are required:
+-----------------+---------------------------------+----------------------+
```
Microcode for D0 stepping cannot be generated from the tree.
Therefore, including external microcode is **mandatory** for boards sold with
D0 stepping (Engineering Sample).
Microcode for those SoCs cannot be generated from the tree.
While boards with D1 (production) stepping may work, microcode Intel had
included in their tree is too old, which causes issues with APIC
(Advanced Programmable Interrupt Controller), resulting in overall instability.
This is **required** for boards sold with D0 SoC revision (Engineering Sample).
Maintainer of this port had included publicly-available [microcodes] in
`3rdparty/blobs` coreboot repository, which are being pulled as submodule.
Microcode binary for D0 stepping is called
`cpu806D0_platC2_ver00000054_2021-05-07_PRD_B0F9E245.bin`.
To choose appropriate microcode for your system, you should choose:
1. If your motherboard uses Engineering Sample (D0) stepping:
- `cpu806D0_platC2_ver00000054_2021-05-07_PRD_B0F9E245.bin`
2. If your motherboard uses retail (D1) stepping:
- `cpu806D1_platC2_ver00000046_2023-02-27_PRD_08E6188A.bin`
It should be selected by going to:
`Chipset -> Include CPU microcode in CBFS (Include external microcode binary)`.
By going to `Chipset -> Include CPU microcode in CBFS
(Include external microcode binary)`
Failure to choose an appropriate microcode will result in:
- MCE (Machine Check Exception) errors.
- Issues with APIC, resulting in random hangs.
- Unstable system RAM, leading to bit flips and data corruption.
Failure to choose an appropriate microcode may result in:
- Bricked (unbootable) board
- Issues with APIC, resulting in random freezes
- MCE (Machine Check Exception) errors
- Unstable system RAM, leading to bit flips and data corruption
There are no extra steps required for FSP.
Both SKUs work perfectly with FSP Intel publishes in their public repository.
@ -82,7 +88,7 @@ despite using mobile SoC and PCH.
- RS232 serial output from IT8613E for debugging (cbmem, Linux)
- Fan control from userspace (IT8613E Environment Controller)
- USB2.0 and 3.0
- HDMI, DisplayPort (iGPU, including audio)
- HDMI (iGPU, including audio)
- Realtek RTL8111 (GbE NIC)
- Realtek ALC897 (integrated audio)
- PCIe x16 4.0 (SoC)
@ -100,14 +106,19 @@ despite using mobile SoC and PCH.
- XMP Profiles (some people reported issues, despite successful tests).
You can enable it by setting `SpdProfileSelected` in `romstage_fsp_params.c`.
See [FSP XMP flags] for configuration options, proceed with caution.
- Sleep states (which were broken on stock as well, RAM loses power in S3).
- Automatic fan control (fans will always spin at 50% - see below).
- PCIe ASPM (results in AER spam in dmesg).
- GOP init on external GPUs (most EDK2 branches do not include module
necessary to load external Option ROMs)
- Sleep states (which were broken on stock as well)
- USB3.2 might take few tries to get detected at full speed
- iGPU DisplayPort (very simple fix, did not have time to fix GPIO)
- Automatic fan control (fans will always spin at 50% - see below)
- 2x USB2.0 FP and M.2 NGFF USB2.0 not mapped (yet)
- PCIe ASPM (results in AER spam in dmesg)
Please ensure to:
- Disable sleep state in your OS.
- Disable sleep state in your OS to prevent data loss
- Configure automatic fan control using pwmconfig
(`modprobe it87 force_id=0x8603`).
(`modprobe it87 force_id=0x8603`)
- Append `pcie_aspm=off` to your kernel commandline to avoid dmesg spam.
## Notes
@ -115,7 +126,7 @@ Please ensure to:
1. Required blobs, if flashing the entire flash chip.
They can be skipped safely if you are planning on flashing
only the `SI_BIOS` region.
- Intel Flash Descriptor (IFD): `fd.bin`
- Intel Flash Descriptor (IFD): `descriptor.bin`
- Intel Management Engine (ME): `me.bin`
Both blobs included in `3rdparty/blobs` repository were extracted
@ -140,21 +151,29 @@ Please ensure to:
- U-Boot
- LinuxBoot (U-Root + Linux kernel)
If you would like to see output on your iGPU before that stage
(for picking a different boot medium or toggling Secure Boot setting),
you need to use [MrChromebox's EDK2] fork and include [GOP driver] for
TigerLake iGPU in your build.
This will allow you to see output of EDK2 (payload, boot picker)
on your monitor connected to iGPU.
If you're planning to primarly use an external card, disable iGPU by
enabling `Chipset -> Disable Integrated GFX Controller (0:2:0)`
and use [MrChromebox's EDK2] tree.
and use [elly's EDK2] tree.
In order to enable loading Option ROMs from PCIe devices, enable:
`Payload -> Load and Execute OpROMs on PCIe devices`
In order to enable loading Option ROMs from PCIe devices, go to:
`Payload -> edk2 additional custom build parameters`
and add the string: `-D LOAD_OPTION_ROMS=TRUE`
This functionality has been tested with following graphics cards,
with following results:
- Nvidia GeForce RTX3080, RTX3090: Works perfectly.
- AMD Radeon RX6600XT, RX7800XT: Works, but requires
`Extend resource window for PCIe devices above 4G` if `Support PCIe
Resizable BARs` is enabled.
- Intel Arc A580: Works, but option
`Extend resource window for PCIe devices above 4G` is **mandatory**.
- Nvidia GeForce RTX3080, RTX3090: Works perfectly
- AMD Radeon RX6600XT, RX7800XT: Works with ReBAR disabled,
no output in EDK2 with ReBAR enabled
- Intel Arc A580: Works with ReBAR disabled,
corrupted framebuffer before modprobing with ReBAR enabled
## Specification
@ -178,5 +197,7 @@ Resizable BARs` is enabled.
[microcodes]: https://github.com/platomav/CPUMicrocodes/tree/master/Intel
[FSP XMP Flags]: https://github.com/intel/FSP/blob/master/TigerLakeFspBinPkg/Client/Include/FspmUpd.h#L586-L591
[MrChromebox's EDK2]: https://github.com/MrChromebox/edk2
[flashrom]: https://flashrom.org/
[elly's EDK2]: https://github.com/ellyq/edk2
[GOP driver]: https://github.com/MrChromebox/blobs/blob/master/soc/intel/tgl/IntelGopDriver.efi
[flashrom]: https://flashrom.org/Flashrom
[flashprog]: https://flashprog.org/wiki/Flashprog

View file

@ -77,4 +77,4 @@ Specifically, it's a Winbond W25Q64FV (3.3V), whose datasheet can be found
[W25Q64FW]: https://www.winbond.com/resource-files/w25q64fw%20revn%2005182017%20sfdp.pdf
[W25Q64FV]: https://www.winbond.com/resource-files/w25q64fv%20revs%2007182017.pdf
[flashrom]: https://flashrom.org/
[flashrom]: https://flashrom.org/Flashrom

View file

@ -130,4 +130,4 @@ output.
[W25Q128JVSIQ]: https://www.winbond.com/resource-files/w25q128jv%20revf%2003272018%20plus.pdf
[W25Q128JVSIM]: https://www.winbond.com/resource-files/w25q128jv%20dtr%20revb%2011042016.pdf
[flashrom]: https://flashrom.org/
[flashrom]: https://flashrom.org/Flashrom

View file

@ -72,4 +72,4 @@ To do this gently take the SPI flash out of its socket and flash with your progr
[FOXCONN D41S]: http://www.foxconnchannel.com/ProductDetail.aspx?T=motherboard&U=en-us0000481
[FOXCONN]: http://www.foxconnchannel.com
[Flashrom]: https://flashrom.org/
[Flashrom]: https://flashrom.org/Flashrom

View file

@ -30,7 +30,9 @@ This motherboard [also works with Libreboot](https://libreboot.org/docs/install/
## Preparation
For more datails how to get sources and build the toolchain, see <project:../../tutorial/part1.md>.
```{eval-rst}
For more datails how to get sources and build the toolchain, see :doc:`../../tutorial/part1`.
```
### Devuan 4 Chimaera
@ -138,8 +140,10 @@ Built gigabyte/ga-g41m-es2l (GA-G41M-ES2L)
## Flashing coreboot
```{eval-rst}
In addition to the information here, please see the
<project:../../tutorial/flashing_firmware/index.md>.
:doc:`../../tutorial/flashing_firmware/index`.
```
### Do backup

View file

@ -77,4 +77,4 @@ However, this makes DualBIOS unable to recover from a bad flash for some reason.
[Gigabyte GA-H61M-S2PV]: https://www.gigabyte.com/us/Motherboard/GA-H61M-S2PV-rev-10
[Gigabyte]: https://www.gigabyte.com
[flashrom]: https://flashrom.org/
[flashrom]: https://flashrom.org/Flashrom

View file

@ -146,4 +146,4 @@ as otherwise there's not enough space near the flash.
[IFD Hack]: https://review.coreboot.org/plugins/gitiles/coreboot/+/refs/changes/70/38770/4/Documentation/flash_tutorial/int_macbook.md/
[Compaq 8200 Elite SFF]: https://support.hp.com/us-en/document/c03414707
[HP]: https://www.hp.com/
[flashrom]: https://flashrom.org/
[flashrom]: https://flashrom.org/Flashrom

View file

@ -39,8 +39,8 @@ The following things are still missing from this coreboot port:
Internal flashing is possible. The SPI flash can be accessed using [flashrom],
but you have to short the FDO pins located near the rear USB3 ports on the
motherboard using a jumper to temporarily disable write protections while on the
stock firmware. Remove the jumper once coreboot is installed.
motherboard using a jumper, to temporarily disable write protections while on the
stock firmware. Once the coreboot rom is flashed, one should remove the jumper.
### External programming
@ -70,4 +70,4 @@ as otherwise there's not enough space near the flash.
[Compaq 8300 Elite SFF]: https://support.hp.com/us-en/document/c03345460
[HP]: https://www.hp.com/
[flashrom]: https://flashrom.org/
[flashrom]: https://flashrom.org/Flashrom

View file

@ -59,8 +59,7 @@ Wake on LAN is active works great.
### SuperIO
This board has a Nuvoton NPCD379 SuperIO chip. Fan speed and PS/2 keyboard work
fine using coreboot's existing code for
<project:../../superio/nuvoton/npcd378.md>.
fine using coreboot's existing code for :doc:`../../superio/nuvoton/npcd378`.
[Compaq Elite 8300 USDT]: https://support.hp.com/gb-en/product/hp-compaq-elite-8300-ultra-slim-pc/5232866
[HP]: https://www.hp.com/

View file

@ -1,109 +0,0 @@
# HP Compaq Pro 6300 Series
This page describes how to run coreboot on the HP [Compaq Pro 6300 Series] desktop.
These come in two versions: Microtower or Small Form Factor (SFF). They share the same
mainboard (657239-001) and Maintenance and Service Guide (690362-003/c04034127). This port has
been tested on a SFF unit.
## Working
- i3-3220 / e3-1225v2 CPUs
- SeaBIOS (version rel-1.16.3-0-ga6ed6b70)
- EDK2 (MrChromebox/2502)
- Fedora-mate with Linux kernels 6.11.4, 6.13.6; KDE neon with Linux kernel 6.8.0 / 6.11.0
- Mixed memory configurations from single 4GB to 24GB total with 1.35v & 1.5v modules
- Integrated Ethernet
- Serial port
- PS/2 keyboard and mouse
- Integrated graphics over DisplayPort and VGA port
- libgfxinit textmode (SeaBIOS) / framebuffer (EDK2)
- discrete GPU's show boot screen using SeaBIOS / EDK2 (LOAD_OPTION_ROMS=TRUE)
- All SATA ports
- All USB2 & USB3 ports
- PCI slot (Realtek RTL8169 GbE card)
- PCIe 3.0 x16 using 2.0 8x 10Gb Intel X540-AT2 / 1.0 16x nVidia GeForce(6200 LE / GT640-2GD3)
- PCIe 2.0 x1 using 2.0 1x 2.5Gb Realtek RTL8125
- PCIe 2.0 x1 using 1.0 1x 1Gb Intel 82574L (SeaBIOS loads option rom)
- Audio built-in speaker (plays music in OS compared to legacy bleep pc-speaker)
- Front panel audio ports (front headphone port overrides built-in speaker; only microphone
works with combo mic/headphone with TRRS plug)
- Back panel audio ports
- Sensors CPU and 4 DIMM jc42-i2c sensors
- Booting USB / SATA(HDD/DVD)
- LEDs HDD, Power(blinks on suspend)
- Shutdown, Reboot, Suspend & Wake (USB keyboard & LAN)
- Strip down Intel ME/TXE firmware and hide MEI device
## Untested
- Parallel port
## Not working
- Simultaneous use of discrete and integrated graphics
## TODO
The following things are still missing from this coreboot port:
- Extended HWM reporting
- Advanced LED control
- Advanced power configuration in S3
## Flashing coreboot
```{eval-rst}
+---------------------+------------+
| Type | Value |
+=====================+============+
| Socketed flash | no |
+---------------------+------------+
| Model | MT25Q128A |
+---------------------+------------+
| Size | 16 MiB |
+---------------------+------------+
| In circuit flashing | yes |
+---------------------+------------+
| Package | SOIC-16 |
+---------------------+------------+
| Write protection | Yes |
+---------------------+------------+
| Dual BIOS feature | No |
+---------------------+------------+
| Internal flashing | yes |
+---------------------+------------+
```
### Internal programming
Internal flashing is possible. The SPI flash can be accessed using [flashrom],
but you have to short the FDO pins located near the rear USB3 ports on the
motherboard using a jumper to temporarily disable write protections while on the
stock firmware. Remove the jumper once coreboot is installed.
### External programming
External programming with an SPI adapter and [flashrom] does work, but it powers the
whole southbridge complex. You need to supply enough current through the programming adapter.
If you want to use a SOIC Pomona test clip, you have to cut the 2nd DRAM DIMM holder,
as otherwise there's not enough space near the flash.
## Technology
```{eval-rst}
+------------------+--------------------------------------------------+
| Northbridge | :doc:`../../northbridge/intel/sandybridge/index` |
+------------------+--------------------------------------------------+
| Southbridge | bd82x6x (Q75) |
+------------------+--------------------------------------------------+
| CPU | model_206ax |
+------------------+--------------------------------------------------+
| SuperIO | Nuvoton NPCD379 |
+------------------+--------------------------------------------------+
| EC | |
+------------------+--------------------------------------------------+
| Coprocessor | Intel ME |
+------------------+--------------------------------------------------+
```
[Compaq Pro 6300 Series]: https://support.hp.com/us-en/product/details/hp-compaq-pro-6300-small-form-factor-pc/model/5232884
[flashrom]: https://flashrom.org/Flashrom

View file

@ -7,9 +7,6 @@ It is implemented in HP notebooks since 2013, and desktops since 2015.
This document talks about some mechanism of HP Sure Start on some machines, and
the method to bypass it.
The method may no longer be applicable to more recent boards. HP has a later
[revision of the whitepaper] from 2019 and there may be others.
## Laptops with SMSC MEC1322 embedded controller
Haswell EliteBook, ZBook and ProBook 600 series use SMSC MEC1322 embedded controller.
@ -60,5 +57,4 @@ located at the high address of the flash chip (and in the protected region),
we can leave it untouched, and do not need to extract the EC firmware to put it in
the coreboot image.
[HP Sure Start Technical Whitepaper]: https://h10032.www1.hp.com/ctg/Manual/c05163901.pdf
[revision of the whitepaper]: https://h10032.www1.hp.com/ctg/Manual/c06216928.pdf
[HP Sure Start Technical Whitepaper]: http://h10032.www1.hp.com/ctg/Manual/c05163901

View file

@ -1,53 +1,43 @@
# HP Pro 3x00 Series
# HP Pro 3500 Series
This page describes how to run coreboot on the [Pro 3400 Series] and [Pro 3500 Series]
desktops from [HP].
This page describes how to run coreboot on the [Pro 3500 Series]
desktop from [HP].
## State
All peripherals should work. Automatic fan control as well as S3 are
working. The board was tested to boot Linux and Windows. EHCI debug
is untested. With disabled ME, the SuperIO will not get CPU
temperatures via PECI and therefore the automatic fan control
will not increase the fan speed.
is untested. When using MrChromebox edk2 with secure boot build in, the
board will hang on each boot for about 20 seconds before continuing.
With disabled ME, the SuperIO will not get CPU temperatures via PECI and
therefore the automatic fan control will not increase the fan speed.
## Flashing coreboot
```{eval-rst}
+---------------------+-----------------------------------------+
| Type | Value |
+=====================+=========================================+
| Socketed flash | No |
+---------------------+-----------------------------------------+
| Model | W25Q32BVSIG (3400) / W25Q64FVSIG (3500) |
+---------------------+-----------------------------------------+
| Size | 4 MiB (3400) / 8 MiB (3500) |
+---------------------+-----------------------------------------+
| In circuit flashing | Yes |
+---------------------+-----------------------------------------+
| Package | SOIC-8 |
+---------------------+-----------------------------------------+
| Write protection | See below |
+---------------------+-----------------------------------------+
| Dual BIOS feature | No |
+---------------------+-----------------------------------------+
| Internal flashing | Yes |
+---------------------+-----------------------------------------+
+---------------------+-------------------------+
| Type | Value |
+=====================+=========================+
| Socketed flash | No |
+---------------------+-------------------------+
| Model | W25Q64FVSIG |
+---------------------+-------------------------+
| Size | 8 MiB |
+---------------------+-------------------------+
| In circuit flashing | Yes |
+---------------------+-------------------------+
| Package | SOIC-8 |
+---------------------+-------------------------+
| Write protection | See below |
+---------------------+-------------------------+
| Dual BIOS feature | No |
+---------------------+-------------------------+
| Internal flashing | Yes |
+---------------------+-------------------------+
```
### Flash layout
The original layout of the flash should look like this:
#### Pro 3400
```
00000000:00000fff fd
00180000:003fffff bios
00001000:0017ffff me
00fff000:00000fff gbe
00fff000:00000fff pd
```
#### Pro 3500
```
00000000:00000fff fd
00400000:007fffff bios
@ -58,7 +48,8 @@ The original layout of the flash should look like this:
### Internal programming
The SPI flash can be accessed using [flashrom].
The SPI flash can be accessed using [flashrom] (although it reports as
"N25Q064..3E", it works fine).
With a missing FDO jumper, `fd` region is read-only, `bios` region is
read-write and `me` region is locked. Vendor firmware will additionally
@ -71,7 +62,9 @@ region will be modified on shutdown. Cut the AC power or do a restart
from the OS.
**Position of FDO jumper (E2) close to the F_USB3**
![FDO jumper position](pro_3x00_series_jumper.avif)
![][pro_3500_jumper]
[pro_3500_jumper]: pro_3500_series_jumper.avif
### External programming
@ -83,7 +76,9 @@ The supply needs to quickly reach 3V3 or else the chip is also unstable
until cleanly power cycled.
**Position of SOIC-8 flash and pin-header near ATX power connector**
![Flash position](pro_3x00_series_flash.avif)
![][pro_3500_flash]
[pro_3500_flash]: pro_3500_series_flash.avif
## Technology
@ -103,7 +98,6 @@ until cleanly power cycled.
+------------------+--------------------------------------------------+
```
[Pro 3400 Series]: https://support.hp.com/us-en/product/details/hp-pro-3400-microtower-pc/5160137
[Pro 3500 Series]: https://support.hp.com/us-en/product/details/hp-pro-3500-microtower-pc/5270849
[Pro 3500 Series]: https://support.hp.com/us-en/document/c03364089
[HP]: https://www.hp.com/
[flashrom]: https://flashrom.org/
[flashrom]: https://flashrom.org/Flashrom

View file

Before

Width:  |  Height:  |  Size: 37 KiB

After

Width:  |  Height:  |  Size: 37 KiB

Before After
Before After

View file

Before

Width:  |  Height:  |  Size: 35 KiB

After

Width:  |  Height:  |  Size: 35 KiB

Before After
Before After

View file

@ -77,4 +77,4 @@ even interchangeable, so should do coreboot images built for them.
[HP Z220 SFF Workstation]: https://support.hp.com/za-en/document/c03386950
[HP Compaq Elite 8300 SFF]: https://support.hp.com/us-en/document/c03345460
[HP]: https://www.hp.com/
[flashrom]: https://flashrom.org/
[flashrom]: https://flashrom.org/Flashrom

View file

@ -43,7 +43,6 @@ IMB-1222 <asrock/imb-1222.md>
A88XM-E <asus/a88xm-e.md>
F2A85-M <asus/f2a85-m.md>
H610i-PLUS D4 <asus/h610i-plus-d4>
P2B-LS <asus/p2b-ls.md>
P3B-F <asus/p3b-f.md>
P5Q <asus/p5q.md>
@ -54,7 +53,6 @@ P8H77-V <asus/p8h77-v.md>
P8Z77-M <asus/p8z77-m.md>
P8Z77-M Pro <asus/p8z77-m_pro.md>
P8Z77-V <asus/p8z77-v.md>
P8Z77-V LE PLUS <asus/p8z77-v_le_plus.md>
wifigo_v1 <asus/wifigo_v1.md>
```
@ -141,8 +139,7 @@ GA-H61M-S2PV <gigabyte/ga-h61m-s2pv.md>
Compaq 8200 Elite SFF <hp/compaq_8200_sff.md>
Compaq 8300 Elite SFF <hp/compaq_8300_sff.md>
Compaq Elite 8300 USDT <hp/compaq_8300_usdt.md>
Compaq Pro 6300 Series Microtower/SFF <hp/compaq_pro_6300_series.md>
Pro 3x00 Series <hp/pro_3x00_series.md>
Pro 3500 Series <hp/pro_3500_series.md>
Z220 Workstation SFF <hp/z220_sff.md>
```
@ -187,8 +184,6 @@ mAL-10 <kontron/mal10.md>
Mainboard codenames <lenovo/codenames.md>
Hardware Maintenance Manual of ThinkPads <lenovo/thinkpad_hmm.md>
R60 <lenovo/r60.md>
ThinkCentre M710s <lenovo/thinkcentre_m710s.md>
ThinkCentre M700 / M900 Tiny <lenovo/thinkcentre_m900_tiny.md>
T4xx common <lenovo/t4xx_series.md>
X2xx common <lenovo/x2xx_series.md>
M920 Tiny <lenovo/m920q.md>
@ -243,13 +238,6 @@ Internal flashing <lenovo/ivb_internal_flashing.md>
T440p <lenovo/t440p.md>
```
### Skylake/Kabylake series
```{toctree}
:maxdepth: 1
T470s/T480/T480s/T580/X280 <lenovo/skylake.md>
```
## Libretrend
```{toctree}
@ -358,10 +346,8 @@ StarBook Mk V <starlabs/starbook_tgl.md>
StarBook Mk VI <starlabs/starbook_adl.md>
StarBook Mk VII (N200) <starlabs/starbook_adl_n.md>
StarBook Mk VII (165H) <starlabs/starbook_mtl.md>
StarBook Horizon <starlabs/adl_horizon.md>
Byte Mk II <starlabs/byte.md>
Byte Mk II <starlabs/byte_adl.md>
StarFighter Mk I <starlabs/starfighter_rpl.md>
StarFighter Mk II <starlabs/starfighter_mtl.md>
Building coreboot <starlabs/common/building.md>
Flashing devices <starlabs/common/flashing.md>

View file

@ -96,4 +96,4 @@ The layout of the header is:
```
[Intel DG43GT]: https://ark.intel.com/products/41036/Intel-Desktop-Board-DG43GT
[flashrom]: https://flashrom.org/
[flashrom]: https://flashrom.org/Flashrom

View file

@ -104,9 +104,11 @@ the PCI configuration space of the LPC Interface Bridge, is set.
It is possible to program the chip is to attach an external programmer
with an SOIC-8 clip.
```{eval-rst}
Another way is to boot the vendor firmware in UEFI mode and exploit the
unpatched S3 Boot Script vulnerability. See this page for a similar procedure:
<project:../lenovo/ivb_internal_flashing.md>.
:doc:`../lenovo/ivb_internal_flashing`.
```
On this specific board it is possible to prevent the BLE bit from being set
when it resumes from S3. One entry in the S3 Boot Script must be modified,
@ -124,10 +126,12 @@ The boot script contains an entry that writes 0x02 to memory at address
Interface Bridge [0][1]. The value 0x02 sets the BLE bit, and the modification
prevents this by making it write a 0 instead.
```{eval-rst}
After suspending and resuming the board, the BIOS region can be flashed with
a coreboot image, e.g. using flashrom. Note that the ME region is not readable,
so the `--noverify-all` flag is necessary. Please refer to the
<project:../../tutorial/flashing_firmware/index.md>.
:doc:`../../tutorial/flashing_firmware/index`.
```
## Hardware monitoring and fan control

View file

@ -76,4 +76,4 @@ $ flashrom -p internal --ifd -i bios -w coreboot.rom --noverify-all
```
[W25Q128FV]: https://www.winbond.com/resource-files/w25q128fv%20rev.m%2005132016%20kms.pdf
[flashrom]: https://flashrom.org/
[flashrom]: https://flashrom.org/Flashrom

View file

@ -95,6 +95,6 @@ close to the CPU.
[mAL10]: https://www.kontron.com/products/iot/iot-industry-4.0/iot-ready-boards-and-modules/com-express/com-express-mini/come-mal10-e2-.html
[W25Q128FV]: https://www.winbond.com/resource-files/w25q128fv%20rev.m%2005132016%20kms.pdf
[flashrom]: https://flashrom.org/
[flashrom]: https://flashrom.org/Flashrom
[NCT7802Y]: https://www.nuvoton.com/products/cloud-computing/hardware-monitors/desktop-server-series/nct7802y/?__locale=en
[crashes]: https://pastebin.com/cpCfrPCL

View file

@ -37,7 +37,9 @@ This information is valid for all supported models, except T430s, [T431s](t431s.
exceed 4MiB in size, which means CONFIG_CBFS_SIZE must be smaller than 4MiB.
* ROM chip size should be set to 12MiB.
Please also have a look at <project:../../tutorial/flashing_firmware/index.md>.
```{eval-rst}
Please also have a look at :doc:`../../tutorial/flashing_firmware/index`.
```
## Splitting the coreboot.rom

View file

@ -98,5 +98,5 @@ Tested with edk2 payload (mrchromebox) and Ubuntu 22.04 (Linux 6.2.0):
- another riser with PCIe x4 connector remains untested - please modify this
page if you do test it!
[flashrom]: https://flashrom.org/
[flashrom]: https://flashrom.org/Flashrom
[Lenovo M920 Tiny specifications]: https://psref.lenovo.com/syspool/Sys/PDF/ThinkCentre/ThinkCentre_M920_Tiny/ThinkCentre_M920_Tiny_Spec.PDF

View file

@ -1,232 +0,0 @@
# Lenovo ThinkPad T470s/T480/T480s/T580/X280
This page describes how to run coreboot on the Lenovo [Thinkpad T470s], [ThinkPad T480],
[Thinkpad T480s], [Thinkpad T580], and [Thinkpad X280].
## Important Notes
### EC UART
The T480 (but not T480s) supports the use of the EC UART for debugging. If you want to use this
feature, you need to downgrade the vendor firmware to a version with a compatible EC firmware
*before flashing* for the EC UART to work properly. The EC firmware version needs to be 1.22
(N24HT37W), which means any BIOS from 1.39 (N24ET64W) to 1.54 (N24ET79W) is acceptable.
The mapping can be seen here [on Lenovo's site].
### Boot Guard
Most Thinkpads newer than the xx30 models except machines with swappable CPUs (T440p, W541) and
some models in the E series (E460, E470) have Intel Boot Guard enabled. This prevents these
laptops from running custom firmware which is not cryptographically signed with the manufacturer's
key.
The [deguard utility](../../soc/intel/deguard) will need to be used in order to bypass Boot Guard
on these devices.
### Thunderbolt
Older versions of Thunderbolt 3 controller firmware are buggy on these laptops.
The issue is that the TB3 firmware writes its logging data to the TB3's own 4M flash chip, and
when the flash chip fills up, the device fails to boot.
Lenovo has addressed this in a TB3 firmware update, which is recommended be be applied before
installing coreboot to ensure long-term reliability of the device. That said, most laptops that
still work likely have this fix already applied, and you can always externally flash the TB3
firmware update at the same time as flashing coreboot.
If your device becomes bricked due to this issue, the only resolution is to externally flash the
updated/fixed TB3 firmware flash (which is located on a separate flash IC from the main firmware).
The Lenovo TB3 FW update can be obtained [from Lenovo's site].
The Libreboot project has some more information about the issue and [how to externally flash the
TB3 firmware].
## Initial Setup
Follow the coreboot [tutorial](../../tutorial/part1) to:
* install dependencies/prerequisites
* clone the coreboot repo
* build the coreboot toolchain
You will also need to clone the [deguard](https://review.coreboot.org/deguard) repository in
order to bypass Boot Guard.
## Required proprietary blobs
When flashing the laptop for the first time, the following blobs are required for a full
flash image:
* Flash Descriptor (IFD)
* Management Engine (ME)
* Gigabit Ethernet (GBE)
These will either be extracted from the vendor firmware on the device or downloaded as needed.
Additionally, all Skylake/Kabylake machines require Intel's Firmware Support Package (FSP) for
hardware initialization. FSP is provided by default as part of the coreboot build, no user
intervention is required.
## Reading the vendor firmware
The Skylake Thinkpads have a single BIOS flash chip (16 MiB serial flash in a SOIC-8 package).
The flash chip uses the following layout:
00000000:00000fff flash descriptor (fd)
00001000:00002fff gbe
00003000:006fffff me
00700000:00ffffff bios
To read the vendor firmware, disconnect external power and remove the back of the laptop
as described in the [hardware maintenance manual](thinkpad_hmm).
Disconnect/remove all batteries (and CMOS battery if equipped). Attach a chip clip to the flash.
Use an external SPI programmer (ch341a, raspberry Pi, etc) to read the chip `bios.bin`.
## Preparing the binaries
The IFD and GBE need to be extracted from the vendor firmware backup read from the flash chip.
See [Extract IFD binaries](../../util/ifdtool/binary_extraction).
ifdtool -x -p sklkbl bios.bin
Rename the extracted files to `ifd.bin` and `gbe.bin` and move them to the `binaries` folder
you created per the instructions.
### Preparing the ME with deguard
Please review the documentation on the use of the [deguard utility](../../soc/intel/deguard).
All Skylake/Kabylake Thinkpads supported by coreboot are also supported in deguard. Hence, we
simply need to download/extract the donor image, then generate the "deguarded" ME firmware
image.
The donor ME binary required for use with the deguard utility can be downloaded as part of the
[Dell firmware updater]. After downloading, use [Dell_PFS_Extract.py] to extract the required ME
firmware image from the updater:
python Dell_PFS_Extract.py Inspiron_5468_1.3.0.exe
The resulting binary should be renamed `me_donor.bin` (file size 0x1f0000 bytes, sha256
`912271bb3ff2cf0e2e27ccfb94337baaca027e6c90b4245f9807a592c8a652e1`) and moved to the `binaries`
folder with the IFD and GBE binaries.
Then, generate the deguarded ME firmware image adjusting the `--delta` argument according to
your laptop's model:
./finalimage.py --delta data/delta/thinkpad_t480 --version 11.6.0.1126 --pch LP --sku 2M --fake-fpfs data/fpfs/zero --input ../coreboot/binaries/me_donor.bin --output ../coreboot/binaries/me_deguarded.bin
The command above assumes you are running deguard from the root of the deguard repo, that the
deguard and coreboot repos are checked out under the same parent directory, and that your ME
donor firmware is in the `binaries` subdirectory of coreboot (along with the IFD/GBE binaries).
Adjust the paths as necessary if that is not the case.
Please be careful with [me_cleaner](../../northbridge/intel/sandybridge/me_cleaner). While
me_cleaner is generally expected to work, truncating the ME binary can have unintended side
effects like disabling PCIe devices on Thinkpad T470s (NVMe, WLAN, WWAN, etc.).
### Preparing the IFD
In order to use the modified ME firmware binary generated by deguard above, we need to set the
HAP bit in the IFD using `ifdtool`:
util/ifdtool/ifdtool -p sklkbl -M 1 binaries/ifd.bin
The modified IFD will be saved as `ifd.bin.new`. Rename the original file to `ifd.bin.orig` and
the HAP-enabled one to `ifd.bin`
If you want to allocate the space that has become available from truncating the ME firmware to
corebios, you can modify the IFD layout. First, save the layout below into a text file
`layout.txt`:
00000000:00000fff fd
001f4000:00ffffff bios
00003000:001f3fff me
00001000:00002fff gbe
Then run ifdtool again:
util/ifdtool/ifdtool -p sklkbl -n layout.txt binaries/ifd.bin
Once again, the modified IFD will be saved as `ifd.bin.new`. Rename `ifd.bin.new` to `ifd.bin`.
The layout above allows you to maximize the CBFS size in your coreboot `.config`:
CONFIG_CBFS_SIZE=0xE0C000
## Building coreboot
You can use `make menuconfig` or `make nconfig` to select the mainboard matching your machine,
enable the inclusion of the IFD/ME/GBE binaries, and select your payload and options.
For example, you can also just use the following defconfig for a Thinkpad T480 with EDK2/UEFI
as a payload:
CONFIG_VENDOR_LENOVO=y
CONFIG_BOARD_LENOVO_T480=y
CONFIG_IFD_BIN_PATH="binaries/ifd.bin"
CONFIG_ME_BIN_PATH="binaries/me_deguarded.bin"
CONFIG_GBE_BIN_PATH="binaries/gbe.bin"
CONFIG_HAVE_IFD_BIN=y
CONFIG_HAVE_ME_BIN=y
CONFIG_HAVE_GBE_BIN=y
CONFIG_PAYLOAD_EDK2=y
Save the above to a file called `defconfig` in your coreboot directory, then run:
make defconfig
make -j"$(nproc)"
Upon successful compilation, you will have a file `coreboot.rom` in the `build` directory ready
to flash.
## Flashing instructions
The initial flash of coreboot with the modified IFD and deguarded ME must be done using an
external programmer:
sudo flashrom -p <programmer> -w coreboot.rom
Subsequent flashes can be done internally and need only modify the `bios` region of the flash:
sudo flashrom -p internal -w coreboot.rom --ifd -i bios -N
The `coreboot.rom` flashed on subsequent flashes does not need to contain the IFD/ME/GBE
binaries if only flashing the `bios` region.
## Known Issues
- Some Fn+F{1-12} keys aren't handled correctly
- Nvidia dGPU is finicky
- Needs option ROM
- Power enable code is buggy
- Proprietary driver does not work at all
- Nouveau only works on linux 6.8-6.9
- Headphone jack detection
- Both headphone jack and speakers work when manually selected via pulseaudio
## Verified Working
- Alpine Ridge Thunderbolt 3 controller
- Integrated graphics init with libgfxinit
- video output: internal (eDP), miniDP
- ACPI support
- keyboard and trackpoint
- SATA
- M.2 SATA SSD
- NVMe
- USB
- Ethernet
- WLAN
- WWAN
- Bluetooth
- Virtualization: VT-x and VT-d
- Internal flashing (after initial flash with unlocked IFD)
[Thinkpad T470s]: https://pcsupport.lenovo.com/us/en/products/laptops-and-netbooks/thinkpad-t-series-laptops/thinkpad-t470s/
[ThinkPad T480]: https://pcsupport.lenovo.com/us/en/products/laptops-and-netbooks/thinkpad-t-series-laptops/thinkpad-t480-type-20l5-20l6/
[ThinkPad T480s]: https://pcsupport.lenovo.com/us/en/products/laptops-and-netbooks/thinkpad-t-series-laptops/thinkpad-t480s-type-20l7-20l8/
[Thinkpad T580]: https://pcsupport.lenovo.com/us/en/products/laptops-and-netbooks/thinkpad-t-series-laptops/thinkpad-t580-type-20l9-20la/
[Thinkpad X280]: https://pcsupport.lenovo.com/us/en/products/laptops-and-netbooks/thinkpad-x-series-laptops/thinkpad-x280-type-20kf-20ke/
[on Lenovo's site]: https://support.lenovo.com/us/en/downloads/ds502355-bios-update-utility-bootable-cd-for-windows-10-64-bit-linux-thinkpad-t480
[from Lenovo's site]: https://pcsupport.lenovo.com/gb/en/products/laptops-and-netbooks/thinkpad-t-series-laptops/thinkpad-t480s-type-20l7-20l8/solutions/ht508988-critical-intel-thunderbolt-software-and-firmware-updates-thinkpad
[how to externally flash the TB3 firmware]: https://libreboot.org/docs/install/t480.html#thunderbolt-issue-read-this-before-flashing
[Dell firmware updater]: https://web.archive.org/web/20241110222323/https://dl.dell.com/FOLDER04573471M/1/Inspiron_5468_1.3.0.exe
[Dell_PFS_Extract.py]: https://github.com/vuquangtrong/Dell-PFS-BIOS-Assembler/blob/master/Dell_PFS_Extract.py

View file

@ -1,81 +0,0 @@
# Lenovo ThinkCentre M710s
This page provides technical documentation on [Lenovo ThinkCentre M710s].
## Flash chip
```{eval-rst}
+----------+-------------+
| Type | Value |
+==========+=============+
| Socketed | yes |
+----------+-------------+
| Model | W25Q64JV-.Q |
+----------+-------------+
| Size | 8MiB |
+----------+-------------+
| Package | SOIC-8 |
+----------+-------------+
```
The flash chip is divided into the following regions.
00000000:00000fff fd
00200000:007fffff bios
00003000:001fffff me
00001000:00002fff gbe
## Flashing
The flash chip cannot be flashed internally when running vendor firmware, and must
be flashed externally using a programmer of your choice.
Steps on how to open the chassis and get access to the mainboard are described
in the [hardware maintenance manual]. Follow the steps shown from
"[Removing the computer cover]" until step 1 of "[Replacing the storage drive]".
The SPI flash should be easy to identify and the location is shown in the image
below. See the [datasheet] and [flashing firmware tutorial] for more information.
![](thinkcentre_m710s_spi_location.jpg)
## Status
### Working
* Ubuntu 22.04.1 (Linux 6.5.0) using payloads:
* SeaBIOS
* MrChromebox's EDK 2 fork
* Tianocore's EDK 2
* Internal flashing (from coreboot)
* PEG (PCIe Graphics)
* PCIe
* SATA
* M.2 SSD
* M.2 WLAN (+ Bluetooth)
* LAN
* USB
* Memory card reader
* CPU fan
* VGA
* Display ports
* Audio (output)
* COM1
* TPM
### Not working
* Super I/O not well supported (there may be some minor issues)
* Power button LED
* ME cleaner
### Untested
* Audio (input)
* COM2 header
* LPT header
* PS/2 keyboard and mouse
[Lenovo ThinkCentre M710s]: https://www.lenovo.com/us/en/p/desktops/thinkcentre/m-series-sff/thinkcentre-m710s/11tc1md710s
[hardware maintenance manual]: https://download.lenovo.com/pccbbs/thinkcentre_pdf/m710s_ug_hmm_en.pdf
[Removing the computer cover]: https://download.lenovo.com/pccbbs/thinkcentre_pdf/m710s_ug_hmm_en.pdf#page=28
[Replacing the storage drive]: https://download.lenovo.com/pccbbs/thinkcentre_pdf/m710s_ug_hmm_en.pdf#page=31
[datasheet]: https://www.winbond.com/hq/product/code-storage-flash-memory/serial-nor-flash/?__locale=en&partNo=W25Q64JV
[flashing firmware tutorial]: ../../tutorial/flashing_firmware/index.md

Binary file not shown.

Before

Width:  |  Height:  |  Size: 82 KiB

View file

@ -1,88 +0,0 @@
# Lenovo ThinkCentre M700 / M900 Tiny
This page provides technical documentation on [Lenovo ThinkCentre M700 / M900 Tiny].
M700 Tiny and M900 Tiny are twin designs using the same exact mainboard, with
the following differences:
```{eval-rst}
+------------------------+------+------+
| Feature | M700 | M900 |
+========================+======+======+
| Chipset | B150 | Q170 |
+------------------------+------+------+
| Intel AMT | No | Yes |
+------------------------+------+------+
| Intel TXT | No | Yes |
+------------------------+------+------+
| PCIe lanes in M.2 slot | No | Yes |
+------------------------+------+------+
```
## Flash chip
```{eval-rst}
+----------+--------------------------+
| Type | Value |
+==========+==========================+
| Socketed | no |
+----------+--------------------------+
| Model | W25Q128.V or MX25L12873F |
+----------+--------------------------+
| Size | 16MiB |
+----------+--------------------------+
| Package | SOIC-8 |
+----------+--------------------------+
```
The flash chip is divided into the following regions.
00000000:00000fff fd
00001000:00002fff gbe
00003000:007fffff me
00800000:00ffffff bios
## Flashing
The flash chip cannot be flashed internally when running vendor firmware, and must
be flashed externally using a programmer of your choice.
Steps on how to open the chassis and get access to the mainboard are described
in the [hardware maintenance manual]. Follow the steps shown from
"[Removing the computer cover]" until "[Replacing the M.2 storage drive]".
The SPI flash should be easy to identify and the location is shown in the image
below. See the [datasheet] and [flashing firmware tutorial] for more information.
![](thinkcentre_m900_tiny_spi_location.jpg)
## Status
### Working
* Debian 12 (Linux 6.1.0) using MrChromebox' EDK II fork (uefipayload_2502)
* M.2 SATA + NVMe slot
* M.2 Wi-Fi slot
* Display ports
* USB
* Audio
* LAN
* CPU fan
* Discrete TPM 1.2
* Internal flashing (from coreboot)
* COM1 header
* DisplayPort header
* Power LED
* S3 Suspend
### Untested
* PS/2 header
* PCIe + SATA "2L" expansion header
[Lenovo ThinkCentre M700 / M900 Tiny]: https://psref.lenovo.com/syspool/Sys/PDF/ThinkCentre/ThinkCentre_M900_Tiny/ThinkCentre_M900_Tiny_Spec.PDF
[hardware maintenance manual]: https://download.lenovo.com/pccbbs/thinkcentre_pdf/m700_m900_m900x_tiny_hmm.pdf
[Removing the computer cover]: https://download.lenovo.com/pccbbs/thinkcentre_pdf/m700_m900_m900x_tiny_hmm.pdf#page=119
[Replacing the M.2 storage drive]: https://download.lenovo.com/pccbbs/thinkcentre_pdf/m700_m900_m900x_tiny_hmm.pdf#page=134
[datasheet]: https://www.mouser.com/datasheet/2/949/w25q128jv_revf_03272018_plus-1489608.pdf
[flashing firmware tutorial]: ../../tutorial/flashing_firmware/index.md

Binary file not shown.

Before

Width:  |  Height:  |  Size: 204 KiB

View file

@ -112,6 +112,6 @@ not publicly available.
[Libretrend LT1000]: https://libretrend.com/specs/librebox/
[W25Q64FV]: https://www.winbond.com/resource-files/w25q64fv%20revs%2007182017.pdf
[flashrom]: https://flashrom.org/
[flashrom]: https://flashrom.org/Flashrom
[baseboard site]: http://www.minicase.net/product_LR-i7S65T1.html
[custom module]: https://shop.3mdeb.com/product/tpm2-module-for-librebox/

View file

@ -219,7 +219,7 @@ and [u-root] as initramfs.
[The Wiwynn's Yosemite-V3 product in OCP market place]: https://www.opencompute.org/products/423/wiwynn-yosemite-v3-server
[osf-builder]: https://github.com/facebookincubator/osf-builder
[OCP virtual summit 2020]: https://www.opencompute.org/summit/virtual-summit/schedule
[flashrom]: https://flashrom.org/
[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

@ -90,7 +90,7 @@ u-root.
+------------------------+---------------------------------------------+
```
[flashrom]: https://flashrom.org/
[flashrom]: https://flashrom.org/Flashrom
[OCP]: https://www.opencompute.org/
[OCP Tioga Pass]: http://files.opencompute.org/oc/public.php?service=files&t=6fc3033e64fb029b0f84be5a8faf47e8
[OCP Market Place]: https://www.opencompute.org/products/109/wiwynn-tioga-pass-advanced-2u-ocp-server-up-to-768gb-12-dimm-slots-4-ssds-for-io-performance

View file

@ -81,4 +81,4 @@ Dediprog compatible pinout.
[Elgon]: https://github.com/Telecominfraproject/OpenCellular
[OpenCellular]: https://code.fb.com/connectivity/introducing-opencellular-an-open-source-wireless-access-platform/
[flashrom]: https://flashrom.org/
[flashrom]: https://flashrom.org/Flashrom

View file

@ -94,4 +94,4 @@ site. Depending on the configuration:
[apu1c1_flash]: apu1c1.jpg
[spi_header]: apu1_spi.jpg
[flashrom]: https://flashrom.org/
[flashrom]: https://flashrom.org/Flashrom

View file

@ -113,4 +113,4 @@ are available for free on PC Engines official site. Both configurations
[apu2_flash]: apu2.jpg
[spi_header]: apu2_spi.jpg
[flashrom]: https://flashrom.org/
[flashrom]: https://flashrom.org/Flashrom

View file

@ -75,5 +75,5 @@ serial/video/pcie ports might be available.
[Portwell PQ7-M107]: http://portwell.com/products/detail.php?CUSTCHAR1=PQ7-M107
[W25Q64FW]: https://www.winbond.com/resource-files/w25q64fw%20revn%2005182017%20sfdp.pdf
[flashrom]: https://flashrom.org/
[flashrom]: https://flashrom.org/Flashrom
[Board manual]: www.portwell.com/pdf/embedded/PQ7-M107.pdf

View file

@ -48,7 +48,7 @@ The board features:
## Extra links
[flashrom]: https://flashrom.org/
[flashrom]: https://flashrom.org/Flashrom
[flashing tutorial]: ../../tutorial/flashing_firmware/ext_power.md
[Intel FSP2.0]: ../../soc/intel/fsp/index.md
[AST2500]: https://www.aspeedtech.com/products.php?fPath=20&rId=440

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