Compare commits
1 commit
main
...
4.22_branc
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
2ff2409037 |
12189 changed files with 124643 additions and 1088077 deletions
|
|
@ -1,6 +1,3 @@
|
|||
# Override checkpatch's default max line length 100
|
||||
--max-line-length=96
|
||||
|
||||
# Not Linux, so don't expect a Linux tree.
|
||||
--no-tree
|
||||
|
||||
|
|
|
|||
249
.clang-format
249
.clang-format
|
|
@ -1,228 +1,21 @@
|
|||
# SPDX-License-Identifier: GPL-2.0-only
|
||||
#
|
||||
# clang-format configuration file. Intended for clang-format >= 16.
|
||||
#
|
||||
# For more information, see:
|
||||
#
|
||||
# https://clang.llvm.org/docs/ClangFormat.html
|
||||
# https://clang.llvm.org/docs/ClangFormatStyleOptions.html
|
||||
# https://clang-format-configurator.site/
|
||||
#
|
||||
|
||||
---
|
||||
Language: Cpp
|
||||
AccessModifierOffset: -4
|
||||
AlignAfterOpenBracket: Align
|
||||
AlignArrayOfStructures: Left
|
||||
AlignConsecutiveAssignments:
|
||||
Enabled: false
|
||||
AcrossEmptyLines: false
|
||||
AcrossComments: true
|
||||
AlignCompound: false
|
||||
PadOperators: true
|
||||
AlignConsecutiveBitFields:
|
||||
Enabled: true
|
||||
AcrossEmptyLines: false
|
||||
AcrossComments: false
|
||||
AlignCompound: false
|
||||
PadOperators: true
|
||||
AlignConsecutiveDeclarations:
|
||||
Enabled: false
|
||||
AcrossEmptyLines: false
|
||||
AcrossComments: false
|
||||
AlignCompound: false
|
||||
PadOperators: true
|
||||
AlignConsecutiveMacros:
|
||||
Enabled: true
|
||||
AcrossEmptyLines: false
|
||||
AcrossComments: false
|
||||
AlignCompound: false
|
||||
PadOperators: true
|
||||
AlignEscapedNewlines: Left
|
||||
AlignOperands: Align
|
||||
AlignTrailingComments:
|
||||
Kind: Always
|
||||
OverEmptyLines: 0
|
||||
AllowAllArgumentsOnNextLine: true
|
||||
AllowAllParametersOfDeclarationOnNextLine: false
|
||||
AllowShortBlocksOnASingleLine: Never
|
||||
AllowShortCaseLabelsOnASingleLine: false
|
||||
AllowShortEnumsOnASingleLine: true
|
||||
AllowShortFunctionsOnASingleLine: None
|
||||
AllowShortIfStatementsOnASingleLine: Never
|
||||
AllowShortLambdasOnASingleLine: All
|
||||
AllowShortLoopsOnASingleLine: false
|
||||
AlwaysBreakAfterDefinitionReturnType: None
|
||||
AlwaysBreakAfterReturnType: None
|
||||
AlwaysBreakBeforeMultilineStrings: false
|
||||
AlwaysBreakTemplateDeclarations: MultiLine
|
||||
|
||||
# git grep '^#define [^[:space:]]*__.*[^[:space:]]*__attribute__' | grep -v "vendorcode\|payloads\|util" | sed "s|.*:||;s|^#define \([^[:space:]]*__[^([:space:]]*\).*$| - '\1'|" | LC_ALL=C sort -u
|
||||
AttributeMacros:
|
||||
- '__aligned'
|
||||
- '__always_inline'
|
||||
- '__always_unused'
|
||||
- '__cpu_driver'
|
||||
- '__fallthrough'
|
||||
- '__maybe_unused'
|
||||
- '__must_check'
|
||||
- '__noreturn'
|
||||
- '__packed'
|
||||
- '__pci_driver'
|
||||
- '__printf'
|
||||
- '__weak'
|
||||
BinPackArguments: true
|
||||
BinPackParameters: true
|
||||
BitFieldColonSpacing: Both
|
||||
BraceWrapping:
|
||||
AfterCaseLabel: false
|
||||
AfterClass: false
|
||||
AfterControlStatement: Never
|
||||
AfterEnum: false
|
||||
AfterExternBlock: false
|
||||
AfterFunction: true
|
||||
AfterNamespace: true
|
||||
AfterObjCDeclaration: false
|
||||
AfterStruct: false
|
||||
AfterUnion: false
|
||||
BeforeCatch: false
|
||||
BeforeElse: false
|
||||
BeforeLambdaBody: false
|
||||
BeforeWhile: false
|
||||
IndentBraces: false
|
||||
SplitEmptyFunction: true
|
||||
SplitEmptyRecord: true
|
||||
SplitEmptyNamespace: true
|
||||
BreakAfterAttributes: Never
|
||||
BreakAfterJavaFieldAnnotations: false
|
||||
BreakArrays: false
|
||||
BreakBeforeBinaryOperators: None
|
||||
BreakBeforeConceptDeclarations: Always
|
||||
BreakBeforeBraces: Custom
|
||||
BreakBeforeInlineASMColon: OnlyMultiline
|
||||
BreakBeforeTernaryOperators: false
|
||||
BreakConstructorInitializers: AfterColon
|
||||
BreakInheritanceList: AfterColon
|
||||
BreakStringLiterals: false
|
||||
ColumnLimit: 96
|
||||
CommentPragmas: '^ IWYU pragma:'
|
||||
CompactNamespaces: false
|
||||
ConstructorInitializerIndentWidth: 8
|
||||
ContinuationIndentWidth: 8
|
||||
Cpp11BracedListStyle: true
|
||||
DerivePointerAlignment: false
|
||||
DisableFormat: false
|
||||
EmptyLineAfterAccessModifier: Never
|
||||
EmptyLineBeforeAccessModifier: LogicalBlock
|
||||
ExperimentalAutoDetectBinPacking: false
|
||||
FixNamespaceComments: false
|
||||
|
||||
# git grep '^#define [^[:space:]]*for_each[^[:space:]]*(' | grep -v "vendorcode\|payloads\|util" | sed "s|.*:||;s|^#define \([^[:space:]]*for_each[^[:space:]]*\)(.*$| - '\1'|" | LC_ALL=C sort -u
|
||||
ForEachMacros:
|
||||
- 'list_for_each'
|
||||
|
||||
# git grep -i '^#define \+if[^[:space:]]*(' | grep -v "vendorcode\|payloads\|util" | sed "s|.*:||;s|^#define \([^[:space:]]*if[^[:space:]]*\)(.*$| - '\1'|I" | grep -v IFIX | LC_ALL=C sort -u
|
||||
IfMacros:
|
||||
- 'IF_CHANNEL_POPULATED'
|
||||
- 'IF_DIMM_POPULATED'
|
||||
- 'IF_RANK_POPULATED'
|
||||
- 'IfBit0'
|
||||
IncludeBlocks: Preserve
|
||||
IncludeIsMainSourceRegex: ''
|
||||
IndentAccessModifiers: false
|
||||
IndentCaseBlocks: false
|
||||
IndentCaseLabels: false
|
||||
IndentExternBlock: AfterExternBlock
|
||||
IndentGotoLabels: false
|
||||
IndentPPDirectives: None
|
||||
IndentRequiresClause: true
|
||||
IndentWidth: 8
|
||||
IndentWrappedFunctionNames: false
|
||||
InsertBraces: false
|
||||
InsertNewlineAtEOF: true
|
||||
InsertTrailingCommas: None
|
||||
IntegerLiteralSeparator:
|
||||
Binary: 0
|
||||
BinaryMinDigits: 0
|
||||
Decimal: 0
|
||||
DecimalMinDigits: 0
|
||||
Hex: 0
|
||||
HexMinDigits: 0
|
||||
JavaScriptQuotes: Leave
|
||||
JavaScriptWrapImports: true
|
||||
KeepEmptyLinesAtTheStartOfBlocks: false
|
||||
LambdaBodyIndentation: Signature
|
||||
LineEnding: LF
|
||||
MacroBlockBegin: ''
|
||||
MacroBlockEnd: ''
|
||||
MaxEmptyLinesToKeep: 1
|
||||
NamespaceIndentation: None
|
||||
ObjCBinPackProtocolList: Auto
|
||||
ObjCBlockIndentWidth: 8
|
||||
ObjCBreakBeforeNestedBlockParam: true
|
||||
ObjCSpaceAfterProperty: true
|
||||
ObjCSpaceBeforeProtocolList: true
|
||||
PackConstructorInitializers: BinPack
|
||||
PenaltyBreakAssignment: 10
|
||||
PenaltyBreakBeforeFirstCallParameter: 30
|
||||
PenaltyBreakComment: 10
|
||||
PenaltyBreakFirstLessLess: 0
|
||||
PenaltyBreakOpenParenthesis: 0
|
||||
PenaltyBreakString: 10
|
||||
PenaltyBreakTemplateDeclaration: 10
|
||||
PenaltyExcessCharacter: 100
|
||||
PenaltyIndentedWhitespace: 0
|
||||
PenaltyReturnTypeOnItsOwnLine: 60
|
||||
PointerAlignment: Right
|
||||
PPIndentWidth: -1
|
||||
QualifierAlignment: Left
|
||||
ReferenceAlignment: Pointer
|
||||
ReflowComments: false
|
||||
RemoveBracesLLVM: false
|
||||
RemoveSemicolon: false
|
||||
RequiresClausePosition: OwnLine
|
||||
RequiresExpressionIndentation: OuterScope
|
||||
SeparateDefinitionBlocks: Leave
|
||||
ShortNamespaceLines: 1
|
||||
SortIncludes: Never
|
||||
SortJavaStaticImport: Before
|
||||
SortUsingDeclarations: Never
|
||||
SpaceAfterCStyleCast: false
|
||||
SpaceAfterLogicalNot: false
|
||||
SpaceAfterTemplateKeyword: true
|
||||
SpaceAroundPointerQualifiers: Default
|
||||
SpaceBeforeAssignmentOperators: true
|
||||
SpaceBeforeCaseColon: false
|
||||
SpaceBeforeCpp11BracedList: false
|
||||
SpaceBeforeCtorInitializerColon: true
|
||||
SpaceBeforeInheritanceColon: true
|
||||
SpaceBeforeParens: ControlStatementsExceptControlMacros
|
||||
SpaceBeforeParensOptions:
|
||||
AfterControlStatements: true
|
||||
AfterForeachMacros: false
|
||||
AfterFunctionDefinitionName: false
|
||||
AfterFunctionDeclarationName: false
|
||||
AfterIfMacros: false
|
||||
AfterOverloadedOperator: false
|
||||
AfterRequiresInClause: false
|
||||
AfterRequiresInExpression: false
|
||||
BeforeNonEmptyParentheses: false
|
||||
SpaceBeforeRangeBasedForLoopColon: true
|
||||
SpaceBeforeSquareBrackets: false
|
||||
SpaceInEmptyBlock: false
|
||||
SpaceInEmptyParentheses: false
|
||||
SpacesBeforeTrailingComments: 1
|
||||
SpacesInAngles: Never
|
||||
SpacesInConditionalStatement: false
|
||||
SpacesInContainerLiterals: false
|
||||
SpacesInCStyleCastParentheses: false
|
||||
SpacesInLineCommentPrefix:
|
||||
Minimum: 1
|
||||
Maximum: 1
|
||||
SpacesInParentheses: false
|
||||
SpacesInSquareBrackets: false
|
||||
Standard: c++17
|
||||
TabWidth: 8
|
||||
UseTab: ForContinuationAndIndentation
|
||||
...
|
||||
|
||||
BasedOnStyle: LLVM
|
||||
Language: Cpp
|
||||
IndentWidth: 8
|
||||
UseTab: Always
|
||||
BreakBeforeBraces: Linux
|
||||
AllowShortIfStatementsOnASingleLine: false
|
||||
IndentCaseLabels: false
|
||||
SortIncludes: false
|
||||
ContinuationIndentWidth: 8
|
||||
ColumnLimit: 96
|
||||
AlwaysBreakBeforeMultilineStrings: true
|
||||
AllowShortLoopsOnASingleLine: false
|
||||
AllowShortFunctionsOnASingleLine: false
|
||||
AlignEscapedNewlinesLeft: false
|
||||
AlignTrailingComments: true
|
||||
AllowAllParametersOfDeclarationOnNextLine: false
|
||||
AlignAfterOpenBracket: true
|
||||
SpaceAfterCStyleCast: false
|
||||
MaxEmptyLinesToKeep: 2
|
||||
BreakBeforeBinaryOperators: NonAssignment
|
||||
BreakStringLiterals: false
|
||||
|
|
|
|||
|
|
@ -9,7 +9,3 @@ charset = utf-8
|
|||
insert_final_newline = true
|
||||
end_of_line = lf
|
||||
trim_trailing_whitespace = true
|
||||
|
||||
[*.sh]
|
||||
indent_style = space
|
||||
indent_size = 2
|
||||
|
|
|
|||
2
.gitignore
vendored
2
.gitignore
vendored
|
|
@ -9,7 +9,6 @@ defconfig
|
|||
build/
|
||||
coreboot-builds/
|
||||
coreboot-builds*/
|
||||
generated/
|
||||
|
||||
site-local
|
||||
|
||||
|
|
@ -35,7 +34,6 @@ tags
|
|||
.cache
|
||||
compile_commands.json
|
||||
.vscode/
|
||||
.clangd
|
||||
|
||||
# Cross-compile toolkits
|
||||
xgcc/
|
||||
|
|
|
|||
51
.gitmodules
vendored
51
.gitmodules
vendored
|
|
@ -1,81 +1,70 @@
|
|||
[submodule "3rdparty/blobs"]
|
||||
path = 3rdparty/blobs
|
||||
url = https://review.coreboot.org/blobs.git
|
||||
url = ../blobs.git
|
||||
update = none
|
||||
ignore = dirty
|
||||
[submodule "util/nvidia-cbootimage"]
|
||||
path = util/nvidia/cbootimage
|
||||
url = https://review.coreboot.org/nvidia-cbootimage.git
|
||||
url = ../nvidia-cbootimage.git
|
||||
[submodule "vboot"]
|
||||
path = 3rdparty/vboot
|
||||
url = https://review.coreboot.org/vboot.git
|
||||
url = ../vboot.git
|
||||
branch = main
|
||||
[submodule "arm-trusted-firmware"]
|
||||
path = 3rdparty/arm-trusted-firmware
|
||||
url = https://review.coreboot.org/arm-trusted-firmware.git
|
||||
url = ../arm-trusted-firmware.git
|
||||
[submodule "3rdparty/chromeec"]
|
||||
path = 3rdparty/chromeec
|
||||
url = ../chrome-ec.git
|
||||
[submodule "libhwbase"]
|
||||
path = 3rdparty/libhwbase
|
||||
url = https://review.coreboot.org/libhwbase.git
|
||||
url = ../libhwbase.git
|
||||
[submodule "libgfxinit"]
|
||||
path = 3rdparty/libgfxinit
|
||||
url = https://review.coreboot.org/libgfxinit.git
|
||||
url = ../libgfxinit.git
|
||||
[submodule "3rdparty/fsp"]
|
||||
path = 3rdparty/fsp
|
||||
url = https://review.coreboot.org/fsp.git
|
||||
url = ../fsp.git
|
||||
update = none
|
||||
ignore = dirty
|
||||
[submodule "opensbi"]
|
||||
path = 3rdparty/opensbi
|
||||
url = https://review.coreboot.org/opensbi.git
|
||||
url = ../opensbi.git
|
||||
[submodule "intel-microcode"]
|
||||
path = 3rdparty/intel-microcode
|
||||
url = https://review.coreboot.org/intel-microcode.git
|
||||
url = ../intel-microcode.git
|
||||
update = none
|
||||
ignore = dirty
|
||||
branch = main
|
||||
[submodule "3rdparty/ffs"]
|
||||
path = 3rdparty/ffs
|
||||
url = https://review.coreboot.org/ffs.git
|
||||
url = ../ffs.git
|
||||
[submodule "3rdparty/amd_blobs"]
|
||||
path = 3rdparty/amd_blobs
|
||||
url = https://review.coreboot.org/amd_blobs
|
||||
url = ../amd_blobs
|
||||
update = none
|
||||
ignore = dirty
|
||||
[submodule "3rdparty/cmocka"]
|
||||
path = 3rdparty/cmocka
|
||||
url = https://review.coreboot.org/cmocka.git
|
||||
url = ../cmocka.git
|
||||
update = none
|
||||
branch = stable-1.1
|
||||
[submodule "3rdparty/qc_blobs"]
|
||||
path = 3rdparty/qc_blobs
|
||||
url = https://review.coreboot.org/qc_blobs.git
|
||||
url = ../qc_blobs.git
|
||||
update = none
|
||||
ignore = dirty
|
||||
[submodule "3rdparty/intel-sec-tools"]
|
||||
path = 3rdparty/intel-sec-tools
|
||||
url = https://review.coreboot.org/9esec-security-tooling.git
|
||||
ignore = dirty
|
||||
url = ../9esec-security-tooling.git
|
||||
[submodule "3rdparty/stm"]
|
||||
path = 3rdparty/stm
|
||||
url = https://review.coreboot.org/STM
|
||||
url = ../STM
|
||||
branch = stmpe
|
||||
[submodule "util/goswid"]
|
||||
path = util/goswid
|
||||
url = https://review.coreboot.org/goswid
|
||||
url = ../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
|
||||
|
||||
url = ../opensil_genoa_poc.git
|
||||
|
|
|
|||
|
|
@ -2,4 +2,4 @@
|
|||
host=review.coreboot.org
|
||||
port=29418
|
||||
project=coreboot
|
||||
defaultbranch=main
|
||||
defaultbranch=master
|
||||
|
|
|
|||
2
3rdparty/amd_blobs
vendored
2
3rdparty/amd_blobs
vendored
|
|
@ -1 +1 @@
|
|||
Subproject commit aa9288a33c6d7a67e55b8757390029207593fa9f
|
||||
Subproject commit e4519efca74615f0f322d595afa7702c64753914
|
||||
2
3rdparty/arm-trusted-firmware
vendored
2
3rdparty/arm-trusted-firmware
vendored
|
|
@ -1 +1 @@
|
|||
Subproject commit 9109143417b24337d39a2a9583828a44996f8aac
|
||||
Subproject commit 88b2d81345dfd84902aae586a743d00ac5df2f48
|
||||
2
3rdparty/blobs
vendored
2
3rdparty/blobs
vendored
|
|
@ -1 +1 @@
|
|||
Subproject commit 4a8de0324e7d389454ec33cdf66939b653bf6800
|
||||
Subproject commit a8db7dfe823def043368857b8fbfbba86f2e9e47
|
||||
1
3rdparty/chromeec
vendored
Submodule
1
3rdparty/chromeec
vendored
Submodule
|
|
@ -0,0 +1 @@
|
|||
Subproject commit e486b388a73f1e19f3142774d0b3ee166e8f41ff
|
||||
2
3rdparty/cmocka
vendored
2
3rdparty/cmocka
vendored
|
|
@ -1 +1 @@
|
|||
Subproject commit 8be37372097d1aa5e03b565936db7891b6180e73
|
||||
Subproject commit 8931845c35e78b5123d73430b071affd537d5935
|
||||
2
3rdparty/fsp
vendored
2
3rdparty/fsp
vendored
|
|
@ -1 +1 @@
|
|||
Subproject commit 81399b3b61479abc379c2d01362d4b6dc6f515c9
|
||||
Subproject commit 481ea7cf0bae0107c3e14aa746e52657647142f3
|
||||
2
3rdparty/intel-microcode
vendored
2
3rdparty/intel-microcode
vendored
|
|
@ -1 +1 @@
|
|||
Subproject commit 250941fb670645d7d91f761cc63656ad3a1ec367
|
||||
Subproject commit 6788bb07eb5f9e9b83c31ea1364150fe898f450a
|
||||
2
3rdparty/libgfxinit
vendored
2
3rdparty/libgfxinit
vendored
|
|
@ -1 +1 @@
|
|||
Subproject commit 3c3828add50024e90e57d6fbe0e660d1b66302d9
|
||||
Subproject commit a4be8a21b0e2c752da0042c79aae5942418f53e2
|
||||
1
3rdparty/open-power-signing-utils
vendored
1
3rdparty/open-power-signing-utils
vendored
|
|
@ -1 +0,0 @@
|
|||
Subproject commit 591c8f53482243626901e1cc8a4ae321f314040d
|
||||
2
3rdparty/qc_blobs
vendored
2
3rdparty/qc_blobs
vendored
|
|
@ -1 +1 @@
|
|||
Subproject commit 6379308814bd00a8b6e36a4715bdb86ba019a3a7
|
||||
Subproject commit a252198ec6544e13904cfe831cec3e784aaa715d
|
||||
2
3rdparty/vboot
vendored
2
3rdparty/vboot
vendored
|
|
@ -1 +1 @@
|
|||
Subproject commit 5c360ef458b0a013d8a6d47724bb0fffb5accbcf
|
||||
Subproject commit 24cb127a5e83a713131ab75cc39b11336019443c
|
||||
137
AUTHORS
137
AUTHORS
|
|
@ -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
|
||||
|
|
@ -41,42 +39,32 @@ Alexandru Gagniuc
|
|||
Alexey Buyanov
|
||||
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
|
||||
Anton Kochkov
|
||||
Ao Zhong
|
||||
Appukuttan V K
|
||||
Arashk Mahshidfar
|
||||
Arec Kao
|
||||
Ariel Fang
|
||||
Ariel Otilibili
|
||||
ARM Limited and Contributors
|
||||
Arthur Heymans
|
||||
Asami Doi
|
||||
|
|
@ -86,12 +74,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,26 +87,20 @@ Bernardo Perez Priego
|
|||
Bhanu Prakash Maiya
|
||||
Bill Xie
|
||||
Bin Meng
|
||||
Bincai Liu
|
||||
Bitland Tech Inc.
|
||||
Bob Moragues
|
||||
Bora Guvendik
|
||||
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
|
||||
Chen-Tsung Hsieh
|
||||
Chen. Gang C
|
||||
Chia-Ling Hou
|
||||
Chien-Chih Tseng
|
||||
Chris Wang
|
||||
|
|
@ -141,7 +120,6 @@ Cong Yang
|
|||
CoolStar
|
||||
coresystems GmbH
|
||||
Corey Osgood
|
||||
Crystal Guo
|
||||
Curt Brune
|
||||
Curtis Chen
|
||||
Custom Ideas
|
||||
|
|
@ -150,7 +128,6 @@ Da Lao
|
|||
Daisuke Nojiri
|
||||
Damien Zammit
|
||||
Dan Callaghan
|
||||
Dan Campbell
|
||||
Daniel Campello
|
||||
Daniel Gröber
|
||||
Daniel Kang
|
||||
|
|
@ -161,7 +138,6 @@ Dave Airlie
|
|||
David Brownell
|
||||
David Greenman
|
||||
David Hendricks
|
||||
David Li
|
||||
David Lin
|
||||
David Milosevic
|
||||
David Mosberger-Tang
|
||||
|
|
@ -171,7 +147,6 @@ David Wu
|
|||
Dawei Chien
|
||||
Deepika Punyamurtula
|
||||
Deepti Deshatty
|
||||
Dehui Sun
|
||||
Denis 'GNUtoo' Carikli
|
||||
Denis Dowling
|
||||
DENX Software Engineering
|
||||
|
|
@ -185,7 +160,6 @@ Divya S Sasidharan
|
|||
Dmitry Ponamorev
|
||||
Dmitry Torokhov
|
||||
DMP Electronics Inc.
|
||||
Dolan Liu
|
||||
Dominik Behr
|
||||
Donghwa Lee
|
||||
Drew Eckhardt
|
||||
|
|
@ -206,10 +180,7 @@ ELSOFT AG
|
|||
Eltan B.V
|
||||
Eltan B.V.
|
||||
Elyes Haouas
|
||||
Emilie Roberts
|
||||
Enzo Potenza
|
||||
Eran Mitrani
|
||||
Eren Peng
|
||||
Eric Biederman
|
||||
Eric Lai
|
||||
Eric Peers
|
||||
|
|
@ -221,21 +192,15 @@ 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
|
||||
Francois Toguo Fotso
|
||||
|
|
@ -249,13 +214,9 @@ Free Software Foundation, Inc.
|
|||
Freescale Semiconductor, Inc.
|
||||
Furquan Shaikh
|
||||
Gaggery Tsai
|
||||
Gang C Chen
|
||||
Garen Wu
|
||||
Gareth Yu
|
||||
Gang C Chen
|
||||
Garmin Chang
|
||||
Gary Jennejohn
|
||||
Gavin Liu
|
||||
George Burgess
|
||||
George Trudeau
|
||||
Gerald Van Baren
|
||||
Gerd Hoffmann
|
||||
|
|
@ -263,7 +224,6 @@ Gergely Kiss
|
|||
Google LLC
|
||||
Greg Watson
|
||||
Grzegorz Bernacki
|
||||
Guangjie Song
|
||||
Guennadi Liakhovetski
|
||||
Guodong Liu
|
||||
Gwendal Grignou
|
||||
|
|
@ -271,21 +231,17 @@ Hal Martin
|
|||
Hao Chou
|
||||
Hao Wang
|
||||
HardenedLinux
|
||||
Harrie Paijmans
|
||||
Harsha B R
|
||||
Harshit Sharma
|
||||
Henry C Chen
|
||||
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 +256,6 @@ Igor Pavlov
|
|||
Ikjoon Jang
|
||||
Imagination Technologies
|
||||
Infineon Technologies
|
||||
Ingo Reitz
|
||||
InKi Dae
|
||||
INSPUR Co., Ltd
|
||||
Intel Corporation
|
||||
|
|
@ -318,14 +273,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 +286,6 @@ 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 +306,9 @@ 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
|
||||
|
|
@ -379,10 +325,7 @@ Jordan Crouse
|
|||
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,12 +334,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
|
||||
Kenneth Chan
|
||||
|
|
@ -407,12 +347,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 +360,6 @@ Kshitij
|
|||
Kshitiz Godara
|
||||
Kulkarni. Srinivas
|
||||
Kun Liu
|
||||
KunYi Chen
|
||||
Kyle Lin
|
||||
Kyösti Mälkki
|
||||
Lance Zhao
|
||||
|
|
@ -430,11 +367,9 @@ Lawrence Chang
|
|||
Leah Rowe
|
||||
Lean Sheng Tan
|
||||
Lei Wen
|
||||
Lennart Eichhorn
|
||||
Lenovo Group Ltd
|
||||
Leo Chou
|
||||
Li-Ta Lo
|
||||
Li1 Feng
|
||||
Liam Flaherty
|
||||
Libra Li
|
||||
Libretrend LDA
|
||||
|
|
@ -445,15 +380,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
|
||||
|
|
@ -467,13 +397,11 @@ Marc Bertens
|
|||
Marc Jones
|
||||
Marco Chen
|
||||
Marek Kasiewicz
|
||||
Marek Maślanka
|
||||
Marek Vasut
|
||||
Mario Scheithauer
|
||||
Marius Gröger
|
||||
Mariusz Szafranski
|
||||
Mariusz Szafrański
|
||||
Mark Chang
|
||||
Mark Hasemeyer
|
||||
Mark Hsieh
|
||||
Mars Chen
|
||||
|
|
@ -484,7 +412,6 @@ Martin Roth
|
|||
Marvell International Ltd.
|
||||
Marvell Semiconductor Inc.
|
||||
Marx Wang
|
||||
Masa Nakura
|
||||
Masanori Ogino
|
||||
Máté Kukri
|
||||
Matei Dibu
|
||||
|
|
@ -493,7 +420,6 @@ Matt Chen
|
|||
Matt Delco
|
||||
Matt DeVillier
|
||||
Matt Papageorge
|
||||
Matt Turner
|
||||
Matthew Blecker
|
||||
Matthew Ziegelbaum
|
||||
Mattias Nissler
|
||||
|
|
@ -506,7 +432,6 @@ Maximilian Brune
|
|||
Mediatek Inc.
|
||||
MediaTek Inc.
|
||||
Meera Ravindranath
|
||||
Melongmelong
|
||||
Meng-Huan Yu
|
||||
Meta Platforms, Inc
|
||||
mgabryelski1
|
||||
|
|
@ -519,20 +444,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,25 +462,21 @@ mtk15698
|
|||
mturney mturney
|
||||
Musse Abdullahi
|
||||
Myles Watson
|
||||
Nancy Lin
|
||||
Nancy.Lin
|
||||
Naresh Solanki
|
||||
Nathan Lu
|
||||
Naveen R. Iyer
|
||||
Neill Corlett
|
||||
Network Appliance Inc.
|
||||
Nicholas Chin
|
||||
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 +490,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
|
||||
|
|
@ -590,7 +502,6 @@ Paul Fagerburg
|
|||
Paul Menzel
|
||||
Paul2 Huang
|
||||
Paulo Alcantara
|
||||
Pavan Holla
|
||||
Pavel Sayekat
|
||||
Paz Zcharya
|
||||
PC Engines GmbH
|
||||
|
|
@ -607,22 +518,17 @@ 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
|
||||
Qualcomm Technologies, Inc.
|
||||
Quanta Computer INC
|
||||
Raihow Shi
|
||||
|
|
@ -637,7 +543,6 @@ Ravindra
|
|||
Ravishankar Sarawadi
|
||||
Ray Han Lim Ng
|
||||
Raymond Chung
|
||||
Reagan
|
||||
Red Hat, Inc
|
||||
ReddestDream
|
||||
Rehan Ghori
|
||||
|
|
@ -655,7 +560,6 @@ Richard Woodruff
|
|||
Rick Lee
|
||||
Ricky Chang
|
||||
Riku Viitanen
|
||||
Rishika Raj
|
||||
Ritul Guru
|
||||
Rizwan Qureshi
|
||||
Rnhmjoj
|
||||
|
|
@ -668,14 +572,12 @@ Robinson P. Tryon
|
|||
Rockchip, Inc.
|
||||
Rocky Phagura
|
||||
Roger Lu
|
||||
Roger Wang
|
||||
Roja Rani Yarubandi
|
||||
Romain Lievin
|
||||
Roman Zippel
|
||||
Ron Lee
|
||||
Ron Minnich
|
||||
Ronak Kanabar
|
||||
Ronald Claveau
|
||||
Ronald G. Minnich
|
||||
Rory Liu
|
||||
Rudolf Marek
|
||||
|
|
@ -697,7 +599,6 @@ Samuel Holland
|
|||
Sandeep Maheswaram
|
||||
Sathya Prakash M R
|
||||
Satya Priya Kakitapalli
|
||||
Satya SreenivasL
|
||||
Saurabh Mishra
|
||||
SciTech Software, Inc.
|
||||
Scott Chao
|
||||
|
|
@ -725,7 +626,6 @@ Shiyu Sun
|
|||
Shon Wang
|
||||
Shou-Chieh Hsu
|
||||
Shreesh Chhabbi
|
||||
Shunxi Zhang
|
||||
Shuo Liu
|
||||
Siemens AG
|
||||
SiFive, Inc
|
||||
|
|
@ -738,12 +638,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 +669,6 @@ Tao Xia
|
|||
Tarun Tuli
|
||||
Teddy Shih
|
||||
Terry Chen
|
||||
Terry Cheong
|
||||
Texas Instruments
|
||||
The Android Open Source Project
|
||||
The ChromiumOS Authors
|
||||
|
|
@ -790,9 +687,7 @@ Timothy Pearson
|
|||
tinghan shen
|
||||
Tobias Diedrich
|
||||
Tom Hiller
|
||||
Tomasz Michalec
|
||||
Tommie Lin
|
||||
Tongtong Pan
|
||||
Tony Huang
|
||||
Tracy Wu
|
||||
Trevor Wu
|
||||
|
|
@ -809,13 +704,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 +716,6 @@ Victor Ding
|
|||
Vidya Gopalakrishnan
|
||||
Vikram Narayanan
|
||||
Vikrant L Jadeja
|
||||
Vince Liu
|
||||
Vinod Polimera
|
||||
Vipin Kumar
|
||||
Vitaly Rodionov
|
||||
|
|
@ -837,10 +728,8 @@ Ward Vandewege
|
|||
Wayne Wang
|
||||
Weimin Wu
|
||||
Weiyi Lu
|
||||
Wen Zhang
|
||||
Wenbin Mei
|
||||
Wentao Qin
|
||||
Wenzhen Yu
|
||||
Werner Zeh
|
||||
Wilbert Duijvenvoorde
|
||||
William Wei
|
||||
|
|
@ -856,19 +745,13 @@ Wojciech Macek
|
|||
Wolfgang Denk
|
||||
Won Chung
|
||||
Wonkyu Kim
|
||||
Wuxy
|
||||
Xiang W
|
||||
Wuxy
|
||||
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,28 +766,20 @@ 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
|
||||
Zhongtian Wu
|
||||
zhongtian wu
|
||||
Zhuohao Lee
|
||||
Ziang Wang
|
||||
Zoey Wu
|
||||
Zoltan Baldaszti
|
||||
一颗小土豆
|
||||
小田喜陽彦
|
||||
忧郁沙茶
|
||||
陳建宏
|
||||
陳建宏
|
||||
|
|
@ -5,7 +5,7 @@
|
|||
#
|
||||
|
||||
BUILDDIR ?= _build
|
||||
SPHINXOPTS ?= -j auto -W --keep-going
|
||||
SPHINXOPTS ?= -j auto
|
||||
|
||||
export SPHINXOPTS
|
||||
|
||||
|
|
@ -31,7 +31,8 @@ livesphinx: $(BUILDDIR)
|
|||
|
||||
test:
|
||||
@echo "Test for logging purposes - Failing tests will not fail the build"
|
||||
-$(MAKE) -f Makefile.sphinx clean && $(MAKE) -k -f Makefile.sphinx html
|
||||
-$(MAKE) -f Makefile.sphinx clean && $(MAKE) -K -f Makefile.sphinx html
|
||||
-$(MAKE) -f Makefile.sphinx clean && $(MAKE) -K -f Makefile.sphinx doctest
|
||||
|
||||
help:
|
||||
@echo "all - Builds all documentation targets"
|
||||
|
|
|
|||
|
|
@ -1,29 +1,234 @@
|
|||
## SPDX-License-Identifier: GPL-2.0-only
|
||||
# Minimal makefile for Sphinx documentation
|
||||
# Makefile for Sphinx documentation
|
||||
#
|
||||
|
||||
# You can set these variables from the command line, and also
|
||||
# from the environment for the first two.
|
||||
SPHINXOPTS ?=
|
||||
SPHINXBUILD ?= sphinx-build
|
||||
SPHINXAUTOBUILD = sphinx-autobuild
|
||||
SOURCEDIR = .
|
||||
BUILDDIR = _build
|
||||
# You can set these variables from the command line.
|
||||
SPHINXOPTS ?=
|
||||
SPHINXBUILD = sphinx-build
|
||||
SPHINXAUTOBUILD = sphinx-autobuild
|
||||
PAPER =
|
||||
BUILDDIR = _build
|
||||
|
||||
# Put it first so that "make" without argument is like "make help".
|
||||
# Internal variables.
|
||||
PAPEROPT_a4 = -D latex_paper_size=a4
|
||||
PAPEROPT_letter = -D latex_paper_size=letter
|
||||
ALLSPHINXOPTS = -d $(BUILDDIR)/doctrees $(PAPEROPT_$(PAPER)) $(SPHINXOPTS) .
|
||||
# the i18n builder cannot share the environment and doctrees with the others
|
||||
I18NSPHINXOPTS = $(PAPEROPT_$(PAPER)) $(SPHINXOPTS) .
|
||||
|
||||
.PHONY: help
|
||||
help:
|
||||
@$(SPHINXBUILD) -M help "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O)
|
||||
@echo "Please use \`make <target>' where <target> is one of"
|
||||
@echo " html to make standalone HTML files"
|
||||
@echo " dirhtml to make HTML files named index.html in directories"
|
||||
@echo " singlehtml to make a single large HTML file"
|
||||
@echo " pickle to make pickle files"
|
||||
@echo " json to make JSON files"
|
||||
@echo " htmlhelp to make HTML files and a HTML help project"
|
||||
@echo " qthelp to make HTML files and a qthelp project"
|
||||
@echo " applehelp to make an Apple Help Book"
|
||||
@echo " devhelp to make HTML files and a Devhelp project"
|
||||
@echo " epub to make an epub"
|
||||
@echo " epub3 to make an epub3"
|
||||
@echo " latex to make LaTeX files, you can set PAPER=a4 or PAPER=letter"
|
||||
@echo " latexpdf to make LaTeX files and run them through pdflatex"
|
||||
@echo " latexpdfja to make LaTeX files and run them through platex/dvipdfmx"
|
||||
@echo " text to make text files"
|
||||
@echo " man to make manual pages"
|
||||
@echo " texinfo to make Texinfo files"
|
||||
@echo " info to make Texinfo files and run them through makeinfo"
|
||||
@echo " gettext to make PO message catalogs"
|
||||
@echo " changes to make an overview of all changed/added/deprecated items"
|
||||
@echo " xml to make Docutils-native XML files"
|
||||
@echo " pseudoxml to make pseudoxml-XML files for display purposes"
|
||||
@echo " linkcheck to check all external links for integrity"
|
||||
@echo " doctest to run all doctests embedded in the documentation (if enabled)"
|
||||
@echo " coverage to run coverage check of the documentation (if enabled)"
|
||||
@echo " dummy to check syntax errors of document sources"
|
||||
|
||||
.PHONY: help Makefile.sphinx
|
||||
.PHONY: clean
|
||||
clean:
|
||||
rm -rf $(BUILDDIR)
|
||||
|
||||
.PHONY: html
|
||||
html:
|
||||
$(SPHINXBUILD) -b html $(ALLSPHINXOPTS) $(BUILDDIR)/html
|
||||
@echo
|
||||
@echo "Build finished. The HTML pages are in $(BUILDDIR)/html."
|
||||
|
||||
.PHONY: livehtml
|
||||
livehtml:
|
||||
@echo "Starting sphinx-autobuild. The HTML pages are in $(BUILDDIR)."
|
||||
@echo "Press Ctrl-C to stop."
|
||||
@echo
|
||||
$(SPHINXAUTOBUILD) "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O)
|
||||
$(SPHINXAUTOBUILD) -b html $(ALLSPHINXOPTS) $(BUILDDIR)
|
||||
|
||||
# Catch-all target: route all unknown targets to Sphinx using the new
|
||||
# "make mode" option. $(O) is meant as a shortcut for $(SPHINXOPTS).
|
||||
%: Makefile.sphinx
|
||||
@$(SPHINXBUILD) -M $@ "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O)
|
||||
.PHONY: dirhtml
|
||||
dirhtml:
|
||||
$(SPHINXBUILD) -b dirhtml $(ALLSPHINXOPTS) $(BUILDDIR)/dirhtml
|
||||
@echo
|
||||
@echo "Build finished. The HTML pages are in $(BUILDDIR)/dirhtml."
|
||||
|
||||
.PHONY: singlehtml
|
||||
singlehtml:
|
||||
$(SPHINXBUILD) -b singlehtml $(ALLSPHINXOPTS) $(BUILDDIR)/singlehtml
|
||||
@echo
|
||||
@echo "Build finished. The HTML page is in $(BUILDDIR)/singlehtml."
|
||||
|
||||
.PHONY: pickle
|
||||
pickle:
|
||||
$(SPHINXBUILD) -b pickle $(ALLSPHINXOPTS) $(BUILDDIR)/pickle
|
||||
@echo
|
||||
@echo "Build finished; now you can process the pickle files."
|
||||
|
||||
.PHONY: json
|
||||
json:
|
||||
$(SPHINXBUILD) -b json $(ALLSPHINXOPTS) $(BUILDDIR)/json
|
||||
@echo
|
||||
@echo "Build finished; now you can process the JSON files."
|
||||
|
||||
.PHONY: htmlhelp
|
||||
htmlhelp:
|
||||
$(SPHINXBUILD) -b htmlhelp $(ALLSPHINXOPTS) $(BUILDDIR)/htmlhelp
|
||||
@echo
|
||||
@echo "Build finished; now you can run HTML Help Workshop with the" \
|
||||
".hhp project file in $(BUILDDIR)/htmlhelp."
|
||||
|
||||
.PHONY: qthelp
|
||||
qthelp:
|
||||
$(SPHINXBUILD) -b qthelp $(ALLSPHINXOPTS) $(BUILDDIR)/qthelp
|
||||
@echo
|
||||
@echo "Build finished; now you can run "qcollectiongenerator" with the" \
|
||||
".qhcp project file in $(BUILDDIR)/qthelp, like this:"
|
||||
@echo "# qcollectiongenerator $(BUILDDIR)/qthelp/coreboot.qhcp"
|
||||
@echo "To view the help file:"
|
||||
@echo "# assistant -collectionFile $(BUILDDIR)/qthelp/coreboot.qhc"
|
||||
|
||||
.PHONY: applehelp
|
||||
applehelp:
|
||||
$(SPHINXBUILD) -b applehelp $(ALLSPHINXOPTS) $(BUILDDIR)/applehelp
|
||||
@echo
|
||||
@echo "Build finished. The help book is in $(BUILDDIR)/applehelp."
|
||||
@echo "N.B. You won't be able to view it unless you put it in" \
|
||||
"~/Library/Documentation/Help or install it in your application" \
|
||||
"bundle."
|
||||
|
||||
.PHONY: devhelp
|
||||
devhelp:
|
||||
$(SPHINXBUILD) -b devhelp $(ALLSPHINXOPTS) $(BUILDDIR)/devhelp
|
||||
@echo
|
||||
@echo "Build finished."
|
||||
@echo "To view the help file:"
|
||||
@echo "# mkdir -p $$HOME/.local/share/devhelp/coreboot"
|
||||
@echo "# ln -s $(BUILDDIR)/devhelp $$HOME/.local/share/devhelp/coreboot"
|
||||
@echo "# devhelp"
|
||||
|
||||
.PHONY: epub
|
||||
epub:
|
||||
$(SPHINXBUILD) -b epub $(ALLSPHINXOPTS) $(BUILDDIR)/epub
|
||||
@echo
|
||||
@echo "Build finished. The epub file is in $(BUILDDIR)/epub."
|
||||
|
||||
.PHONY: epub3
|
||||
epub3:
|
||||
$(SPHINXBUILD) -b epub3 $(ALLSPHINXOPTS) $(BUILDDIR)/epub3
|
||||
@echo
|
||||
@echo "Build finished. The epub3 file is in $(BUILDDIR)/epub3."
|
||||
|
||||
.PHONY: latex
|
||||
latex:
|
||||
$(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex
|
||||
@echo
|
||||
@echo "Build finished; the LaTeX files are in $(BUILDDIR)/latex."
|
||||
@echo "Run \`make' in that directory to run these through (pdf)latex" \
|
||||
"(use \`make latexpdf' here to do that automatically)."
|
||||
|
||||
.PHONY: latexpdf
|
||||
latexpdf:
|
||||
$(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex
|
||||
@echo "Running LaTeX files through pdflatex..."
|
||||
$(MAKE) -C $(BUILDDIR)/latex all-pdf
|
||||
@echo "pdflatex finished; the PDF files are in $(BUILDDIR)/latex."
|
||||
|
||||
.PHONY: latexpdfja
|
||||
latexpdfja:
|
||||
$(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex
|
||||
@echo "Running LaTeX files through platex and dvipdfmx..."
|
||||
$(MAKE) -C $(BUILDDIR)/latex all-pdf-ja
|
||||
@echo "pdflatex finished; the PDF files are in $(BUILDDIR)/latex."
|
||||
|
||||
.PHONY: text
|
||||
text:
|
||||
$(SPHINXBUILD) -b text $(ALLSPHINXOPTS) $(BUILDDIR)/text
|
||||
@echo
|
||||
@echo "Build finished. The text files are in $(BUILDDIR)/text."
|
||||
|
||||
.PHONY: man
|
||||
man:
|
||||
$(SPHINXBUILD) -b man $(ALLSPHINXOPTS) $(BUILDDIR)/man
|
||||
@echo
|
||||
@echo "Build finished. The manual pages are in $(BUILDDIR)/man."
|
||||
|
||||
.PHONY: texinfo
|
||||
texinfo:
|
||||
$(SPHINXBUILD) -b texinfo $(ALLSPHINXOPTS) $(BUILDDIR)/texinfo
|
||||
@echo
|
||||
@echo "Build finished. The Texinfo files are in $(BUILDDIR)/texinfo."
|
||||
@echo "Run \`make' in that directory to run these through makeinfo" \
|
||||
"(use \`make info' here to do that automatically)."
|
||||
|
||||
.PHONY: info
|
||||
info:
|
||||
$(SPHINXBUILD) -b texinfo $(ALLSPHINXOPTS) $(BUILDDIR)/texinfo
|
||||
@echo "Running Texinfo files through makeinfo..."
|
||||
make -C $(BUILDDIR)/texinfo info
|
||||
@echo "makeinfo finished; the Info files are in $(BUILDDIR)/texinfo."
|
||||
|
||||
.PHONY: gettext
|
||||
gettext:
|
||||
$(SPHINXBUILD) -b gettext $(I18NSPHINXOPTS) $(BUILDDIR)/locale
|
||||
@echo
|
||||
@echo "Build finished. The message catalogs are in $(BUILDDIR)/locale."
|
||||
|
||||
.PHONY: changes
|
||||
changes:
|
||||
$(SPHINXBUILD) -b changes $(ALLSPHINXOPTS) $(BUILDDIR)/changes
|
||||
@echo
|
||||
@echo "The overview file is in $(BUILDDIR)/changes."
|
||||
|
||||
.PHONY: linkcheck
|
||||
linkcheck:
|
||||
$(SPHINXBUILD) -b linkcheck $(ALLSPHINXOPTS) $(BUILDDIR)/linkcheck
|
||||
@echo
|
||||
@echo "Link check complete; look for any errors in the above output " \
|
||||
"or in $(BUILDDIR)/linkcheck/output.txt."
|
||||
|
||||
.PHONY: doctest
|
||||
doctest:
|
||||
$(SPHINXBUILD) -b doctest $(ALLSPHINXOPTS) $(BUILDDIR)/doctest
|
||||
@echo "Testing of doctests in the sources finished, look at the " \
|
||||
"results in $(BUILDDIR)/doctest/output.txt."
|
||||
|
||||
.PHONY: coverage
|
||||
coverage:
|
||||
$(SPHINXBUILD) -b coverage $(ALLSPHINXOPTS) $(BUILDDIR)/coverage
|
||||
@echo "Testing of coverage in the sources finished, look at the " \
|
||||
"results in $(BUILDDIR)/coverage/python.txt."
|
||||
|
||||
.PHONY: xml
|
||||
xml:
|
||||
$(SPHINXBUILD) -b xml $(ALLSPHINXOPTS) $(BUILDDIR)/xml
|
||||
@echo
|
||||
@echo "Build finished. The XML files are in $(BUILDDIR)/xml."
|
||||
|
||||
.PHONY: pseudoxml
|
||||
pseudoxml:
|
||||
$(SPHINXBUILD) -b pseudoxml $(ALLSPHINXOPTS) $(BUILDDIR)/pseudoxml
|
||||
@echo
|
||||
@echo "Build finished. The pseudo-XML files are in $(BUILDDIR)/pseudoxml."
|
||||
|
||||
.PHONY: dummy
|
||||
dummy:
|
||||
$(SPHINXBUILD) -b dummy $(ALLSPHINXOPTS) $(BUILDDIR)/dummy
|
||||
@echo
|
||||
@echo "Build finished. Dummy builder generates no files."
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -1,7 +1,3 @@
|
|||
```{eval-rst}
|
||||
:orphan:
|
||||
```
|
||||
|
||||
# Background
|
||||
|
||||
CB:31250 ("soc/intel/cannonlake: Configure GPIOs again after FSP-S is
|
||||
|
|
|
|||
|
|
@ -5,27 +5,15 @@ backwards support for ACPI 1.0 and is only compatible to ACPI version 2.0 and
|
|||
upwards.
|
||||
|
||||
|
||||
```{toctree}
|
||||
:maxdepth: 1
|
||||
|
||||
SSDT UID generation <uid.md>
|
||||
```
|
||||
- [SSDT UID generation](uid.md)
|
||||
|
||||
## GPIO
|
||||
|
||||
```{toctree}
|
||||
:maxdepth: 1
|
||||
|
||||
GPIO toggling in ACPI AML <gpio.md>
|
||||
```
|
||||
- [GPIO toggling in ACPI AML](gpio.md)
|
||||
|
||||
## Windows-specific ACPI documentation
|
||||
|
||||
```{toctree}
|
||||
:maxdepth: 1
|
||||
|
||||
Windows-specific documentation <windows.md>
|
||||
```
|
||||
- [Windows-specific documentation](windows.md)
|
||||
|
||||
## ACPI specification - Useful links
|
||||
|
||||
|
|
|
|||
|
|
@ -18,7 +18,6 @@ Spec](https://uefi.org/specifications) for details, or run the tool
|
|||
initialization that happens from the PSP. Significantly, Memory
|
||||
Initialization.
|
||||
* AC - Electricity: [**Alternating Current**](https://en.wikipedia.org/wiki/Alternating_current)
|
||||
* ACE - AXI Coherency Extensions
|
||||
* Ack - Acknowledgment / Acknowledged
|
||||
* ACM – [**Authenticated Code Module**](https://doc.coreboot.org/security/intel/acm.html)
|
||||
* ACP - [**Average CPU power**](https://en.wikipedia.org/wiki/Thermal_design_power)
|
||||
|
|
@ -57,14 +56,11 @@ Spec](https://uefi.org/specifications) for details, or run the tool
|
|||
* AMT - Intel: [**Active Management Technology**](https://en.wikipedia.org/wiki/Intel_Active_Management_Technology)
|
||||
* ANSI - [**American National Standards Institute**](https://en.wikipedia.org/wiki/American_National_Standards_Institute)
|
||||
* AOAC - AMD: Always On, Always Connected
|
||||
* AON - Always ON: Sometimes used for power domains that are always on (e.g. RTC, GPIOs, Wake on LAN ...)
|
||||
* AP - Application processor - The main processor on the board (as
|
||||
opposed to the embedded controller or other processors that may be on
|
||||
the system), any cores in the processor chip that aren't the BSP (Boot
|
||||
Strap Processor).
|
||||
* APB - Advanced Peripheral Bus (part of the AMBA bus specification)
|
||||
* APCB - AMD: AMD PSP Customization Block
|
||||
* AHB - Advanced High-performance Bus (part of the AMBA bus specification)
|
||||
* API - [**Application Programming Interface**](https://en.wikipedia.org/wiki/API)
|
||||
* APIC - [**Advanced Programmable Interrupt
|
||||
Controller**](https://en.wikipedia.org/wiki/Advanced_Programmable_Interrupt_Controller)
|
||||
|
|
@ -98,7 +94,7 @@ Spec](https://uefi.org/specifications) for details, or run the tool
|
|||
* ATAPI - [**ATA Packet Interface**](https://en.wikipedia.org/wiki/Parallel_ATA#ATAPI)
|
||||
* ATX - [**Advanced Technology eXtended**](https://en.wikipedia.org/wiki/ATX)
|
||||
* AVX - [**Advanced Vector Extensions**](https://en.wikipedia.org/wiki/Advanced_Vector_Extensions)
|
||||
* AXI - [Advanced eXtensible Interface](https://en.wikipedia.org/wiki/Advanced_eXtensible_Interface) part of the AMBA bus specification
|
||||
|
||||
|
||||
## B
|
||||
|
||||
|
|
@ -173,7 +169,6 @@ Spec](https://uefi.org/specifications) for details, or run the tool
|
|||
* CDN - [**Content Delivery Network**](https://en.wikipedia.org/wiki/Content_delivery_network)
|
||||
* CEM - PCIe: [**Card ElectroMechanical**](https://members.pcisig.com/wg/PCI-SIG/document/folder/839) specification
|
||||
* CFL - [**Coffee Lake**](https://en.wikichip.org/wiki/intel/microarchitectures/coffee_lake)
|
||||
* CHI - Coherent Hub Interface
|
||||
* CID - [**Coverity ID**](https://en.wikipedia.org/wiki/Coverity)
|
||||
* CIM - [**Common Information Model**](https://www.dmtf.org/standards/cim)
|
||||
* CISC - [**Complex Instruction Set Computer**](https://en.wikipedia.org/wiki/Complex_instruction_set_computer)
|
||||
|
|
@ -204,6 +199,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
|
||||
|
|
@ -408,7 +404,7 @@ Spec](https://uefi.org/specifications) for details, or run the tool
|
|||
* GPD - PCH GPIO in Deep Sleep well (D5 power)
|
||||
* GPE - ACPI: General Purpose Event
|
||||
* GPI - GPIOs: GPIO Input
|
||||
* GPIO - [**General Purpose Input/Output**](https://en.wikipedia.org/wiki/General-purpose_input/output) (Pin)
|
||||
* GPIO - [**General Purpose Input/Output**](https://en.wikipedia.org/wiki/General-purpose_Input/Output) (Pin)
|
||||
* GPMR - Intel: General Purpose Memory Range
|
||||
* GPO - GPIOs: GPIO Output
|
||||
* GPP - AMD: General Purpose (PCI/PCIe) port
|
||||
|
|
@ -521,7 +517,6 @@ Spec](https://uefi.org/specifications) for details, or run the tool
|
|||
processor to help offload data processing from various sensors on a
|
||||
mainboard.
|
||||
* ISP - Internet Service Provider
|
||||
* ISP - Image-Signal-Process
|
||||
* IVHD - ACPI: I/O Virtualization Hardware Definition
|
||||
* IVMD - ACPI: I/O Virtualization Memory Definition
|
||||
* IVRS - I/O Virtualization Reporting Structure
|
||||
|
|
@ -995,7 +990,6 @@ Spec](https://uefi.org/specifications) for details, or run the tool
|
|||
* SSPHY - USB: USB3 Super-Speed PHY
|
||||
* STAPM - AMD: Skin Temperature Aware Power Management
|
||||
* STB - AMD: Smart Trace Buffer
|
||||
* STG - System-Top-Group apparently a term for grouping subsystems in an SOC together?
|
||||
* SuperIO - The [**Super I/O**](https://en.wikipedia.org/wiki/Super_I/O)
|
||||
(SIO) device provides a system with any of a number of different
|
||||
peripherals. Most common are: A PS/2 Keyboard and mouse port, LPT
|
||||
|
|
|
|||
|
|
@ -5,15 +5,7 @@ architectures.
|
|||
|
||||
## RISC-V
|
||||
|
||||
```{toctree}
|
||||
:maxdepth: 1
|
||||
|
||||
RISC-V documentation <riscv/index.md>
|
||||
```
|
||||
- [RISC-V documentation](riscv/index.md)
|
||||
|
||||
## x86
|
||||
```{toctree}
|
||||
:maxdepth: 1
|
||||
|
||||
x86 documentation <x86/index.md>
|
||||
```
|
||||
- [x86 documentation](x86/index.md)
|
||||
|
|
|
|||
|
|
@ -2,9 +2,94 @@
|
|||
|
||||
This section contains documentation about coreboot on x86 architecture.
|
||||
|
||||
```{toctree}
|
||||
:maxdepth: 1
|
||||
* [x86 PAE support](pae.md)
|
||||
|
||||
x86 PAE support <pae.md>
|
||||
x86_64 support <x86_64.md>
|
||||
```
|
||||
## State of x86_64 support
|
||||
At the moment there's only experimental x86_64 support.
|
||||
The `emulation/qemu-i440fx` and `emulation/qemu-q35` boards do support
|
||||
*ARCH_RAMSTAGE_X86_64* , *ARCH_POSTCAR_X86_64* and *ARCH_ROMSTAGE_X86_64*.
|
||||
|
||||
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
|
||||
* The CPU supports 1GiB hugepages
|
||||
* 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
|
||||
* [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
|
||||
* Must reside in SMRAM
|
||||
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
|
||||
* Test libgfxinit / VGA Option ROMs / FSP
|
||||
|
||||
## Known bugs on real hardware
|
||||
|
||||
According to Intel x86_64 mode hasn't been validated in CAR environments.
|
||||
Until now it could be verified on various Intel platforms and no issues have
|
||||
been found.
|
||||
|
||||
## 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.
|
||||
|
|
|
|||
|
|
@ -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.
|
||||
|
|
@ -86,13 +86,8 @@ organizers may take any action they deem appropriate, up to and including
|
|||
a temporary ban or permanent expulsion from the community without warning
|
||||
(and without refund in the case of a paid event).
|
||||
|
||||
As a part of running the project, coreboot leadership has the right to
|
||||
revoke privileges as they see fit. This is not done lightly. Over the
|
||||
history of the coreboot project, there have been only a handful of times
|
||||
where an action needed to be taken.
|
||||
|
||||
Community organizers can be members of the arbitration team, the
|
||||
leadership board, or organizers of events and online communities.
|
||||
Community organizers can be members of the arbitration team, or organizers
|
||||
of events and online communities.
|
||||
|
||||
## Addressing Grievances
|
||||
|
||||
|
|
@ -100,11 +95,6 @@ If you feel you have been falsely or unfairly accused of violating this
|
|||
Code of Conduct, you should notify the arbitration team with a concise
|
||||
description of your grievance.
|
||||
|
||||
Discussions about these actions are not done publicly, for obvious
|
||||
reasons. If someone believes that the circumstances that led to an
|
||||
action have changed, please send an email to all the members of the
|
||||
arbitration team and/or leadership board for discussion.
|
||||
|
||||
## Legal action
|
||||
|
||||
Threatening or starting legal action against the project, sibling
|
||||
|
|
@ -125,18 +115,12 @@ communications pertaining to community business.
|
|||
|
||||
## Contact info
|
||||
|
||||
Our arbitration team currently consists of the following people
|
||||
* Daniel Pono Takamori <pono@sfconservancy.org> (USA)
|
||||
Our arbitration team consists of the following people
|
||||
* Stefan Reinauer <stefan.reinauer@coreboot.org> (USA)
|
||||
* Patrick Georgi <patrick@coreboot.org> (Germany)
|
||||
* Ronald Minnich <rminnich@coreboot.org> (USA)
|
||||
* Martin Roth <martin@coreboot.org> (USA)
|
||||
|
||||
If you have an issue with someone on the arbitration team, please reach
|
||||
out to the coreboot leadership board directly.
|
||||
|
||||
The leadership board's information can be found on the
|
||||
[coreboot Leadership and Admin Boards](https://coreboot.org/leadership.html)
|
||||
page on the website.
|
||||
|
||||
## License and attribution
|
||||
|
||||
This Code of Conduct is distributed under
|
||||
|
|
|
|||
|
|
@ -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 it’s 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.
|
||||
|
|
@ -1,11 +1,6 @@
|
|||
# Community
|
||||
|
||||
```{toctree}
|
||||
:maxdepth: 1
|
||||
|
||||
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>
|
||||
```
|
||||
* [Code of Conduct](code_of_conduct.md)
|
||||
* [Language style](language_style.md)
|
||||
* [Community forums](forums.md)
|
||||
* [coreboot at conferences](conferences.md)
|
||||
|
|
|
|||
|
|
@ -1,35 +1,54 @@
|
|||
# Configuration file for the Sphinx documentation builder.
|
||||
#
|
||||
# For the full list of built-in configuration values, see the documentation:
|
||||
# https://www.sphinx-doc.org/en/master/usage/configuration.html
|
||||
|
||||
# -- Project information -----------------------------------------------------
|
||||
# https://www.sphinx-doc.org/en/master/usage/configuration.html#project-information
|
||||
|
||||
# -*- coding: utf-8 -*-
|
||||
import subprocess
|
||||
from recommonmark.parser import CommonMarkParser
|
||||
import sphinx
|
||||
|
||||
project = 'coreboot'
|
||||
copyright = 'CC-by 4.0 the coreboot project'
|
||||
author = 'the coreboot project'
|
||||
# Get Sphinx version
|
||||
major = 0
|
||||
minor = 0
|
||||
patchlevel = 0
|
||||
version = sphinx.__version__.split(".")
|
||||
if len(version) > 1:
|
||||
major = int(version[0])
|
||||
minor = int(version[1])
|
||||
if len(version) > 2:
|
||||
patchlevel = int(version[2])
|
||||
|
||||
# Add any paths that contain templates here, relative to this directory.
|
||||
templates_path = ['_templates']
|
||||
|
||||
# The suffix(es) of source filenames.
|
||||
source_suffix = ['.md']
|
||||
|
||||
# The master toctree document.
|
||||
master_doc = 'index'
|
||||
|
||||
# General information about the project.
|
||||
project = u'coreboot'
|
||||
copyright = u'CC-by 4.0 the coreboot project'
|
||||
author = u'the coreboot project'
|
||||
|
||||
# The version info for the project you're documenting, acts as replacement for
|
||||
# |version| and |release|, also used in various other places throughout the
|
||||
# built documents.
|
||||
#
|
||||
# The full version, including alpha/beta/rc tags.
|
||||
release = subprocess.check_output(('git', 'describe')).decode("utf-8")
|
||||
# The short X.Y version.
|
||||
version = release.split("-")[0]
|
||||
|
||||
extensions = []
|
||||
# Load recommonmark, supported since 1.8+
|
||||
if major >= 2 or (major == 1 and minor >= 8):
|
||||
extensions += ['recommonmark']
|
||||
|
||||
# -- General configuration ---------------------------------------------------
|
||||
# https://www.sphinx-doc.org/en/master/usage/configuration.html#general-configuration
|
||||
|
||||
extensions = ["myst_parser"]
|
||||
|
||||
myst_heading_anchors = 5
|
||||
myst_url_schemes = ["http", "https", "mailto", "ftp", "ircs"]
|
||||
|
||||
templates_path = ['_templates']
|
||||
exclude_patterns = ['_build', 'Thumbs.db', '.DS_Store']
|
||||
|
||||
# The name of the Pygments (syntax highlighting) style to use.
|
||||
pygments_style = 'sphinx'
|
||||
# Try to load DITAA
|
||||
try:
|
||||
import sphinxcontrib.ditaa
|
||||
except ImportError:
|
||||
print("Error: Please install sphinxcontrib.ditaa for ASCII art conversion\n")
|
||||
else:
|
||||
extensions += ['sphinxcontrib.ditaa']
|
||||
|
||||
# The language for content autogenerated by Sphinx. Refer to documentation
|
||||
# for a list of supported languages.
|
||||
|
|
@ -38,11 +57,62 @@ pygments_style = 'sphinx'
|
|||
# Usually you set "language" from the command line for these cases.
|
||||
language = 'en'
|
||||
|
||||
# -- Options for HTML output -------------------------------------------------
|
||||
# https://www.sphinx-doc.org/en/master/usage/configuration.html#options-for-html-output
|
||||
# List of patterns, relative to source directory, that match files and
|
||||
# directories to ignore when looking for source files.
|
||||
# This patterns also effect to html_static_path and html_extra_path
|
||||
exclude_patterns = ['_build', 'Thumbs.db', '.DS_Store']
|
||||
|
||||
# The name of the Pygments (syntax highlighting) style to use.
|
||||
pygments_style = 'sphinx'
|
||||
|
||||
# A list of ignored prefixes for module index sorting.
|
||||
# modindex_common_prefix = []
|
||||
|
||||
# If true, keep warnings as "system message" paragraphs in the built documents.
|
||||
# keep_warnings = False
|
||||
|
||||
# If true, `todo` and `todoList` produce output, else they produce nothing.
|
||||
todo_include_todos = False
|
||||
|
||||
|
||||
# -- Options for HTML output ----------------------------------------------
|
||||
|
||||
# The theme to use for HTML and HTML Help pages. See the documentation for
|
||||
# a list of builtin themes.
|
||||
#
|
||||
html_theme = 'sphinx_rtd_theme'
|
||||
|
||||
# Add any paths that contain custom static files (such as style sheets) here,
|
||||
# relative to this directory. They are copied after the builtin static files,
|
||||
# so a file named "default.css" will overwrite the builtin "default.css".
|
||||
html_static_path = ['_static']
|
||||
|
||||
html_css_files = [
|
||||
'theme_overrides.css', # override wide tables in RTD theme
|
||||
]
|
||||
|
||||
# Output file base name for HTML help builder.
|
||||
htmlhelp_basename = 'corebootdoc'
|
||||
|
||||
enable_auto_toc_tree = True
|
||||
|
||||
class MyCommonMarkParser(CommonMarkParser):
|
||||
# remove this hack once upstream RecommonMark supports inline code
|
||||
def visit_code(self, mdnode):
|
||||
from docutils import nodes
|
||||
n = nodes.literal(mdnode.literal, mdnode.literal)
|
||||
self.current_node.append(n)
|
||||
|
||||
def setup(app):
|
||||
from recommonmark.transform import AutoStructify
|
||||
# Load recommonmark on old Sphinx
|
||||
if major == 1 and minor < 8:
|
||||
app.add_source_parser('.md', MyCommonMarkParser)
|
||||
|
||||
app.add_config_value('recommonmark_config', {
|
||||
'enable_auto_toc_tree': True,
|
||||
'enable_auto_doc_ref': False, # broken in Sphinx 1.6+
|
||||
'enable_eval_rst': True,
|
||||
'url_resolver': lambda url: '/' + url
|
||||
}, True)
|
||||
app.add_transform(AutoStructify)
|
||||
|
|
|
|||
|
|
@ -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.
|
||||
*
|
||||
|
|
@ -808,7 +808,7 @@ eDP display panel encounters an I2C error, it should print a "cannot read EDID"
|
|||
message and return an error code. The calling display initialization function
|
||||
knows that without the EDID there is no way to initialize the display correctly,
|
||||
so it will also immediately return with an error code without running its
|
||||
remaining code that would initialize the SoC's display controller. Execution
|
||||
remaining code that would initialize the SoC's display controller. Exeuction
|
||||
returns further up the function stack to the mainboard initialization code
|
||||
which continues booting despite the failed display initialization, since
|
||||
display functionality is non-essential to the system. (Code is encouraged but
|
||||
|
|
|
|||
|
|
@ -304,7 +304,7 @@ would be a good reviewer, look in the MAINTAINERS file or git history of
|
|||
the files that you’ve changed, and add those people.
|
||||
|
||||
* Familiarize yourself with the coreboot [commit message
|
||||
guidelines](#commit-message-guidelines), before pushing
|
||||
guidelines](https://www.coreboot.org/Git#Commit_messages), before pushing
|
||||
patches. This will help to keep annoying requests to fix your commit
|
||||
message to a minimum.
|
||||
|
||||
|
|
@ -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
|
||||
|
|
@ -395,8 +395,8 @@ Gerrit user roles
|
|||
There are a few relevant roles a user can have on Gerrit:
|
||||
|
||||
- The anonymous user can check out source code.
|
||||
- A registered user can also comment and give "+1" code reviews.
|
||||
- A reviewer can give "-1" and "+2" code reviews.
|
||||
- A registered user can also comment and give "+1" and "-1" code reviews.
|
||||
- A reviewer can also give "+2" code reviews.
|
||||
- A core developer can also give "-2" (that is, blocking) code reviews
|
||||
and submit changes.
|
||||
|
||||
|
|
@ -433,55 +433,8 @@ reversed after they come back.
|
|||
Requests for clarification and suggestions for updates to these guidelines
|
||||
should be sent to the coreboot mailing list at <coreboot@coreboot.org>.
|
||||
|
||||
Commit message guidelines
|
||||
-------------------------
|
||||
Git does not enforce a certain style for commit messages. For all aspects of
|
||||
Git to work best with, it's important to follow these simple guidelines for
|
||||
commit messages:
|
||||
|
||||
* The first line of the commit message consists of a short
|
||||
(less than 65 characters, absolute maximum is 75) summary
|
||||
* The second line is empty (no whitespace at all)
|
||||
* The third and any following number of lines contains a longer description
|
||||
of the commit as is necessary, including relevant background information
|
||||
and quite possibly rationale for why the issue was solved in this particular
|
||||
way. These lines should never be longer than 75 characters.
|
||||
* The next line is empty (no whitespace at all)
|
||||
* An optional TEST= line which describes the test that was done in order to
|
||||
validate the patch
|
||||
* An optional BUG= line to reference to a bug (of [coreboot's bug tracker] or any
|
||||
other) this patch resolves
|
||||
* The next line is empty if the optional lines are used
|
||||
* A Change-Id: line to let Gerrit track this logical change
|
||||
* A Signed-off-by: line according to [Signed-off-by policy](#sign-off-procedure)
|
||||
|
||||
Please do not create the Change-Id: and Signed-off-by: entries manually because
|
||||
it is boring and error-prone. Instead, please install the commit-msg hook, e.g.
|
||||
by running
|
||||
```Bash
|
||||
make gitconfig
|
||||
```
|
||||
in coreboot's top-level directory, and let the hook script do it for you.
|
||||
And remember to always use
|
||||
```Bash
|
||||
git commit -s
|
||||
```
|
||||
to have git add your Signed-off-by: automatically.
|
||||
|
||||
When you write your commit message, please keep the following two hints in mind:
|
||||
|
||||
* If anyone involved in coreboot reads your comment in a year or so, they
|
||||
shall still be able to understand what your commit is about, without the need
|
||||
to analyze the code.
|
||||
* Double-check that you are really committing what you think you are, e.g. by
|
||||
typing the following in the top-level coreboot directory:
|
||||
```Bash
|
||||
git show
|
||||
```
|
||||
|
||||
[ready changes]: https://review.coreboot.org/q/age:1d+project:coreboot+status:open+is:mergeable+label:All-Comments-Resolved%253Dok+label:Code-Review%253D2+-label:Code-Review%253C0+label:Verified%253D1+-label:Verified-1
|
||||
[Developer's Certificate of Origin 1.1]: https://developercertificate.org/
|
||||
[Creative Commons Attribution-ShareAlike 2.5 License]: https://creativecommons.org/licenses/by-sa/2.5/
|
||||
[this LKML thread]: https://lkml.org/lkml/2004/5/23/10
|
||||
[SCO-Linux disputes]: https://en.wikipedia.org/wiki/SCO%E2%80%93Linux_disputes
|
||||
[coreboot's bug tracker]: https://ticket.coreboot.org/
|
||||
|
|
|
|||
|
|
@ -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.
|
||||
|
|
@ -1,29 +1,7 @@
|
|||
# Contributing
|
||||
|
||||
```{toctree}
|
||||
:maxdepth: 1
|
||||
|
||||
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
|
||||
* [Coding Style](coding_style.md)
|
||||
* [Gerrit Guidelines](gerrit_guidelines.md)
|
||||
* [Project Ideas](project_ideas.md)
|
||||
* [Documentation Ideas](documentation_ideas.md)
|
||||
* [Google Summer of Code](gsoc.md)
|
||||
|
|
|
|||
|
|
@ -29,7 +29,7 @@ sealings are sent via encrypted email.
|
|||
|
||||
### NovaCustom laptops
|
||||
|
||||
[NovaCustom](https://novacustom.com) sells configurable laptops with
|
||||
[NovaCustom](https://configurelaptop.eu/) sells configurable laptops with
|
||||
[Dasharo](https://dasharo.com/) coreboot based firmware on board, maintained by
|
||||
[3mdeb](https://3mdeb.com/). NovaCustom offers full GNU/Linux and Microsoft
|
||||
Windows compatibility. NovaCustom ensures security updates via fwupd for 5 years
|
||||
|
|
@ -43,16 +43,6 @@ ships with coreboot and support upstream maintenance for the devices through a
|
|||
third party, [3mdeb](https://3mdeb.com). They provide current and tested
|
||||
firmware binaries on [GitHub](https://pcengines.github.io).
|
||||
|
||||
### Protectli
|
||||
|
||||
[Protectli](https://protectli.com) is dedicated to providing reliable,
|
||||
cost-effective, and secure computer equipment with coreboot-based firmware
|
||||
tailored for their hardware. It comes with the [Dasharo](#dasharo)
|
||||
firmware, maintained by [3mdeb](https://3mdeb.com/). Protectli hardware has
|
||||
verified support for many popular operating systems, such as Linux distributions,
|
||||
FreeBSD, and Windows. Support includes Debian, Ubuntu, OPNsense, pfSense,
|
||||
ProxMox VE, VMware ESXi, Windows 10 and 11, and many more.
|
||||
|
||||
### Purism
|
||||
|
||||
[Purism](https://www.puri.sm) sells laptops with a focus on user privacy and
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
||||
|
|
@ -1,297 +0,0 @@
|
|||
# CFR - coreboot form representation
|
||||
|
||||
This documents the API exposed by coreboot to be consumed by
|
||||
loaded OS image or payload.
|
||||
|
||||
## Problem Statement
|
||||
|
||||
As per coreboot design there's no UI present to change firmware
|
||||
related options like "Hyper-Theading Enable". There's no way of
|
||||
knowing what options are supported, if they are supported in the
|
||||
current configuration and what they do.
|
||||
|
||||
The `USE_OPTION_TABLE` Kconfig allows to integrate a list of
|
||||
mainboard specific options into coreboot tables when the option
|
||||
API is using the *CMOS NVRAM*. It has no meaning if another option
|
||||
API is being used.
|
||||
|
||||
## Design Proposal
|
||||
|
||||
Propose a new coreboot table that is independent from the option
|
||||
backend. The coreboot table is generated from coreboot ramstage
|
||||
code.
|
||||
|
||||
Every possible boot option is described by its name, the user
|
||||
visible name, a help text, a default value and status flags.
|
||||
All strings are in ASCII.
|
||||
|
||||
The boot options are grouped into forms, where each form hold
|
||||
one or more options. Boot options that are not used in the current
|
||||
boot flow, and are never reachable should be marked as hidden.
|
||||
Dependecies between options can be defined in the code and should
|
||||
be evaluated by the CFR parser/UI.
|
||||
|
||||
A boot option can be one of the following types:
|
||||
- boolean
|
||||
- number
|
||||
- enum
|
||||
- string
|
||||
|
||||
All of the information is *Position Independent Data*. That is, it is
|
||||
safe to relocate any of the information without its meaning/correctness
|
||||
changing.
|
||||
|
||||
CFR records form a tree structure. Every record starts with a `tag`
|
||||
and a `size` field as generic header:
|
||||
|
||||
```C
|
||||
struct __packed lb_cfr_header {
|
||||
uint32_t tag;
|
||||
uint32_t size;
|
||||
};
|
||||
```
|
||||
|
||||
The size of a record includes the size of its own fields plus the size of all
|
||||
child records. A record can have none or multiple child records.
|
||||
The record `tag` must be known by the parser to parse the record and its
|
||||
sub records. If it is not known to the parser it can simply skip it by
|
||||
jumping `size` bytes forward.
|
||||
|
||||
The coreboot table containing the CFR tree has the tag `LB_TAG_CFR`.
|
||||
|
||||
The public API can be found in
|
||||
`src/commonlib/include/commonlib/cfr.h` and
|
||||
`src/commonlib/include/commonlib/coreboot_tables.h`.
|
||||
|
||||
## Implementation design
|
||||
### Tags
|
||||
Tags identify the structure defined in `src/commonlib/include/commonlib/cfr.h`.
|
||||
Every struct might be immediately followed by additional structs (so called
|
||||
sub nodes), having their own tag and size field. The sum of all sub nodes size
|
||||
fields plus the size of the struct itself equals the size field.
|
||||
|
||||
* CFR_TAG_OPTION_FORM
|
||||
|
||||
Used in `struct lb_cfr_option_form` to describe a group of options. Every
|
||||
sub node is one option that should be displayed in the order found in
|
||||
memory.
|
||||
|
||||
Allowed sub nodes:
|
||||
- `CFR_TAG_OPTION_ENUM`
|
||||
- `CFR_TAG_OPTION_NUMBER`
|
||||
- `CFR_TAG_OPTION_BOOL`
|
||||
- `CFR_TAG_OPTION_VARCHAR`
|
||||
- `CFR_TAG_OPTION_FORM`
|
||||
- `CFR_TAG_OPTION_COMMENT`
|
||||
- `CFR_TAG_VARCHAR_UI_NAME`
|
||||
|
||||
Required sub nodes:
|
||||
- `CFR_TAG_VARCHAR_UI_NAME`
|
||||
|
||||
* CFR_TAG_ENUM_VALUE
|
||||
|
||||
Used in `struct lb_cfr_enum_value` to describe a numeric value to be
|
||||
used in a parent `CFR_TAG_OPTION_ENUM`.
|
||||
|
||||
Allowed sub nodes:
|
||||
- `CFR_TAG_VARCHAR_UI_NAME`
|
||||
|
||||
Required sub nodes:
|
||||
- `CFR_TAG_VARCHAR_UI_NAME`
|
||||
|
||||
* CFR_TAG_OPTION_ENUM
|
||||
|
||||
Used in `struct lb_cfr_numeric_option` to describe a numeric variable with
|
||||
a predefined selection of possible values in the referenced variable.
|
||||
|
||||
Allowed sub nodes:
|
||||
- `CFR_TAG_VARCHAR_OPT_NAME`
|
||||
- `CFR_TAG_VARCHAR_UI_NAME`
|
||||
- `CFR_TAG_ENUM_VALUE`
|
||||
- `CFR_TAG_VARCHAR_UI_HELPTEXT`
|
||||
|
||||
Required sub nodes:
|
||||
- `CFR_TAG_VARCHAR_OPT_NAME`
|
||||
- `CFR_TAG_VARCHAR_UI_NAME`
|
||||
- `CFR_TAG_ENUM_VALUE`
|
||||
|
||||
* CFR_TAG_OPTION_NUMBER
|
||||
|
||||
Used in `struct lb_cfr_numeric_option` to describe a numeric variable with
|
||||
any possible value in the referenced variable.
|
||||
|
||||
Allowed sub nodes:
|
||||
- `CFR_TAG_VARCHAR_OPT_NAME`
|
||||
- `CFR_TAG_VARCHAR_UI_NAME`
|
||||
- `CFR_TAG_VARCHAR_UI_HELPTEXT`
|
||||
|
||||
Required sub nodes:
|
||||
- `CFR_TAG_VARCHAR_OPT_NAME`
|
||||
- `CFR_TAG_VARCHAR_UI_NAME`
|
||||
|
||||
* CFR_TAG_OPTION_BOOL
|
||||
|
||||
Used in `struct lb_cfr_numeric_option` to describe a numeric variable with
|
||||
the possible values [0, 1] in the referenced variable.
|
||||
|
||||
Allowed sub nodes:
|
||||
- `CFR_TAG_VARCHAR_OPT_NAME`
|
||||
- `CFR_TAG_VARCHAR_UI_NAME`
|
||||
- `CFR_TAG_VARCHAR_UI_HELPTEXT`
|
||||
|
||||
Required sub nodes:
|
||||
- `CFR_TAG_VARCHAR_OPT_NAME`
|
||||
- `CFR_TAG_VARCHAR_UI_NAME`
|
||||
|
||||
* CFR_TAG_OPTION_VARCHAR
|
||||
|
||||
Used in `struct lb_cfr_varchar_option` to describe an ASCII string
|
||||
stored in the referenced variable.
|
||||
|
||||
*Example:* Linux kernel cmdline.
|
||||
|
||||
Allowed sub nodes:
|
||||
- `CFR_TAG_VARCHAR_DEF_VALUE`
|
||||
- `CFR_TAG_VARCHAR_OPT_NAME`
|
||||
- `CFR_TAG_VARCHAR_UI_NAME`
|
||||
- `CFR_TAG_VARCHAR_UI_HELPTEXT`
|
||||
|
||||
Required sub nodes:
|
||||
- `CFR_TAG_VARCHAR_DEF_VALUE`
|
||||
- `CFR_TAG_VARCHAR_OPT_NAME`
|
||||
- `CFR_TAG_VARCHAR_UI_NAME`
|
||||
|
||||
* CFR_TAG_OPTION_COMMENT
|
||||
|
||||
Used in `struct lb_cfr_option_comment` to describe an ASCII string visible
|
||||
to the user, but doesn't reference a variable. Informal use only.
|
||||
|
||||
Allowed sub nodes:
|
||||
- `CFR_TAG_VARCHAR_UI_NAME`
|
||||
- `CFR_TAG_VARCHAR_UI_HELPTEXT`
|
||||
|
||||
Required sub nodes:
|
||||
- `CFR_TAG_VARCHAR_UI_NAME`
|
||||
|
||||
* CFR_TAG_VARCHAR_OPT_NAME
|
||||
|
||||
Used in `struct lb_cfr_varbinary` to describe the option name used by
|
||||
coreboot's code. It thus must match what is used in code by
|
||||
`get_uint_option()`.
|
||||
|
||||
Is not user visible.
|
||||
|
||||
* CFR_TAG_VARCHAR_UI_NAME
|
||||
|
||||
Used in `struct lb_cfr_varbinary`
|
||||
|
||||
User visible name of the option.
|
||||
|
||||
* CFR_TAG_VARCHAR_UI_HELPTEXT
|
||||
|
||||
Used in `struct lb_cfr_varbinary`
|
||||
|
||||
Optional user visible description what is changed by this option.
|
||||
|
||||
* CFR_TAG_VARCHAR_DEF_VALUE
|
||||
|
||||
Used in `struct lb_cfr_varbinary`
|
||||
|
||||
Default value in case the variable is not present.
|
||||
|
||||
### Flags
|
||||
|
||||
The optional flags describe the visibilty of the option and the
|
||||
effect on the non-volatile variable.
|
||||
|
||||
* `CFR_OPTFLAG_READONLY`
|
||||
|
||||
Prevents writes to the variable.
|
||||
|
||||
* `CFR_OPTFLAG_INACTIVE`
|
||||
|
||||
Implies `READONLY`. The option is visible, but cannot be modified
|
||||
because one of the dependencies are not given. However there's a
|
||||
possibility to enable the option by changing runtime configuration.
|
||||
|
||||
*For example:* Setting SATA mode, but SATA is globally disabled.
|
||||
|
||||
* `CFR_OPTFLAG_SUPPRESS`
|
||||
|
||||
Runtime code sets this flag to indicate that the option has no effect
|
||||
and is never reachable, not even by changing runtime configuration.
|
||||
This option is never shown in the UI.
|
||||
|
||||
* `CFR_OPTFLAG_VOLATILE`
|
||||
|
||||
Implies `READONLY`.
|
||||
The option is not backed by a non-volatile variable. This is useful
|
||||
to display the current state of a specific component, a dependency or
|
||||
a serial number. This information could be passed in a new coreboot
|
||||
table, but it not useful other than to be shown at this spot in the
|
||||
UI.
|
||||
|
||||
* `CFR_OPTFLAG_RUNTIME`
|
||||
|
||||
The option is allowed to be changed by a post payload entity. On UEFI
|
||||
this sets the `EFI_VARIABLE_RUNTIME_ACCESS` attribute.
|
||||
It is out of scope of this specification how non runtime variables
|
||||
are protected after the payload has hand over control.
|
||||
|
||||
### Example
|
||||
|
||||
To display a boolean option with the label `Boolean`, that default value
|
||||
is `true`, on a form called `test`, that modifies the variable `First`
|
||||
the following structure will be generated:
|
||||
|
||||
```
|
||||
struct lb_cfr_option_form {
|
||||
uint32_t tag; = CFR_TAG_OPTION_FORM
|
||||
uint32_t size; = sizeof(struct lb_cfr_option_form) +
|
||||
sizeof(struct lb_cfr_varbinary) +
|
||||
strlen(name) + 1 + 3 +
|
||||
sizeof(struct lb_cfr_numeric_option) +
|
||||
sizeof(struct lb_cfr_varbinary) +
|
||||
strlen(optname) + 1 + 2 +
|
||||
sizeof(struct lb_cfr_varbinary) +
|
||||
strlen(uiname) + 1 = 120
|
||||
uint64_t object_id; = 1
|
||||
uint64_t dependency_id; = 0
|
||||
uint32_t flags; = 0
|
||||
}
|
||||
struct lb_cfr_varbinary {
|
||||
uint32_t tag; = CFR_TAG_VARCHAR_UI_NAME
|
||||
uint32_t size; = sizeof(struct lb_cfr_varbinary) +
|
||||
strlen(name) + 1 + 3 = 20
|
||||
uint32_t data_length; = strlen(name) + 1
|
||||
};
|
||||
char name[5]; = "test"
|
||||
char padding[3];
|
||||
struct lb_cfr_numeric_option {
|
||||
uint32_t tag; = CFR_TAG_OPTION_BOOL
|
||||
uint32_t size; = sizeof(struct lb_cfr_numeric_option) +
|
||||
sizeof(struct lb_cfr_varbinary) +
|
||||
strlen(optname) + 1 + 2 +
|
||||
sizeof(struct lb_cfr_varbinary) +
|
||||
strlen(uiname) + 1 = 72
|
||||
uint64_t object_id; = 2
|
||||
uint64_t dependency_id; = 0
|
||||
uint32_t flags; = 0
|
||||
uint32_t default_value; = true
|
||||
};
|
||||
struct lb_cfr_varbinary {
|
||||
uint32_t tag; = CFR_TAG_VARCHAR_OPT_NAME
|
||||
uint32_t size; = sizeof(struct lb_cfr_varbinary) +
|
||||
strlen(optname) + 1 + 2 = 20
|
||||
uint32_t data_length; = strlen(optname) + 1 = 6
|
||||
};
|
||||
char optname[6]; = "First"
|
||||
char padding[2];
|
||||
struct lb_cfr_varbinary {
|
||||
uint32_t tag; = CFR_TAG_VARCHAR_UI_NAME
|
||||
uint32_t size; = sizeof(struct lb_cfr_varbinary) +
|
||||
strlen(uiname) + 1 = 20
|
||||
uint32_t data_length; = strlen(uiname) + 1 = 8
|
||||
};
|
||||
char uiname[8]; = "Boolean"
|
||||
```
|
||||
|
|
@ -1,190 +0,0 @@
|
|||
# CFR - coreboot form representation - Internals
|
||||
|
||||
This documents the API internally used by coreboot to be used
|
||||
by ramstage code.
|
||||
|
||||
Please read [CFR](cfr.md) first.
|
||||
|
||||
## Enabling CFR support
|
||||
|
||||
Users should select `DRIVERS_OPTION_CFR` in Kconfig to enable CFR
|
||||
support. Mainboards should select `DRIVERS_OPTION_CFR_ENABLED` to
|
||||
enable `DRIVERS_OPTION_CFR` by default.
|
||||
|
||||
## Using CFR
|
||||
|
||||
When CFR support is enabled there are two possibilites to generate
|
||||
the records:
|
||||
|
||||
- mainboard specific code
|
||||
- automatic collection
|
||||
|
||||
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.
|
||||
You can use a callback, using the `WITH_CALLBACK()` macro, to update
|
||||
single or multiple options when the CFR table is written into the
|
||||
coreboot table.
|
||||
|
||||
**Example:** Updates the option serial_number with the contents from the
|
||||
EMI eeprom.
|
||||
|
||||
```
|
||||
static void update_serial(struct sm_object *new)
|
||||
{
|
||||
new->sm_varchar.default_value = get_emi_eeprom_vpd()->serial_number;
|
||||
}
|
||||
|
||||
static const struct sm_object serial_number = SM_DECLARE_VARCHAR({
|
||||
.flags = CFR_OPTFLAG_READONLY | CFR_OPTFLAG_VOLATILE,
|
||||
.opt_name = "serial_number",
|
||||
.ui_name = "Serial Number",
|
||||
}, WITH_CALLBACK(update_serial));
|
||||
```
|
||||
|
||||
### Dependencies in CFR options
|
||||
|
||||
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.
|
||||
|
||||
**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.
|
||||
When the user changes "sata_enable" to 1 or it was 1 then the option
|
||||
`sata_disable_port0` should be visible.
|
||||
|
||||
```
|
||||
static struct sm_object sata_enable = SM_DECLARE_BOOL({
|
||||
.flags = CFR_OPTFLAG_RUNTIME,
|
||||
.opt_name = "sata_enable",
|
||||
.ui_name = "Enable SATA controller",
|
||||
.ui_helptext = NULL,
|
||||
.default_value = true,
|
||||
});
|
||||
|
||||
static struct sm_object sata_disable_port0 = SM_DECLARE_BOOL({
|
||||
.flags = CFR_OPTFLAG_RUNTIME,
|
||||
.opt_name = "sata_disable_port0",
|
||||
.ui_name = "Disable SATA port #0",
|
||||
.ui_helptext = NULL,
|
||||
.default_value = false,
|
||||
}, 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
|
||||
be overwriting the weak `void mb_cfr_setup_menu(struct lb_cfr *cfr_root);`
|
||||
function in ramstage.
|
||||
|
||||
### Automatic CFR collection
|
||||
|
||||
CFR forms that have the `__cfr_form` attribute are automatically collected
|
||||
and inserted into the coreboot table.
|
||||
|
||||
## Example
|
||||
|
||||
The following CFR form `southbridge` will be automatically added to the
|
||||
coreboot table and it will have a single option called `Enable NMI` that
|
||||
allows the variable `nmi` to be changed to *0* or *1*.
|
||||
|
||||
**Example:**
|
||||
```C
|
||||
static struct sm_object nmi = SM_DECLARE_BOOL({
|
||||
.flags = CFR_OPTFLAG_RUNTIME,
|
||||
.opt_name = "nmi",
|
||||
.ui_name = "Enable NMI",
|
||||
.ui_helptext = NULL,
|
||||
.default_value = false,
|
||||
});
|
||||
|
||||
static const __cfr_form struct sm_obj_form southbridge = {
|
||||
.flags = 0,
|
||||
.ui_name = "Southbridge",
|
||||
.obj_list = (const struct sm_object *[]) {
|
||||
&nmi,
|
||||
NULL
|
||||
},
|
||||
};
|
||||
```
|
||||
|
|
@ -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.
|
||||
|
|
@ -6,28 +6,12 @@ they allow to easily reuse existing code across platforms.
|
|||
|
||||
For details on how to connect device drivers to a mainboard, see [Driver Devicetree Entries](dt_entries.md).
|
||||
|
||||
```{toctree}
|
||||
:maxdepth: 1
|
||||
:hidden:
|
||||
|
||||
Driver Devicetree Entries <dt_entries.md>
|
||||
```
|
||||
|
||||
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>
|
||||
```
|
||||
* [Intel DPTF](dptf.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)
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
@ -128,8 +128,7 @@ data or modify the currently running kernel.*
|
|||
|
||||
## 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)
|
||||
|
||||
* [A Tour Beyond BIOS Implementing UEFI Authenticated Variables in SMM with EDKI](https://software.intel.com/sites/default/files/managed/cf/ea/a_tour_beyond_bios_implementing_uefi_authenticated_variables_in_smm_with_edkii.pdf)
|
||||
Note, this differs significantly from coreboot's implementation.
|
||||
|
||||
[SMM]: ../security/smm.md
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
@ -135,9 +124,25 @@ additional calling arguments are passed via `%ebx`.
|
|||
**NOTE**: The size of the struct entries are in the native word size of
|
||||
smihandler. This means 32 bits in almost all cases.
|
||||
|
||||
#### - SMMSTORE_CMD_INIT_DEPRECATED = 4
|
||||
#### - SMMSTORE_CMD_INIT = 4
|
||||
|
||||
Unused, returns SMMSTORE_REG_UNSUPPORTED.
|
||||
This installs the communication buffer to use and thus enables the
|
||||
SMMSTORE handler. This command can only be executed once and is done
|
||||
by the firmware. Calling this function at runtime has no effect.
|
||||
|
||||
The additional parameter buffer `%ebx` contains a pointer to the
|
||||
following struct:
|
||||
|
||||
```C
|
||||
struct smmstore_params_init {
|
||||
uint32_t com_buffer;
|
||||
uint32_t com_buffer_size;
|
||||
} __packed;
|
||||
```
|
||||
|
||||
INPUT:
|
||||
- `com_buffer`: Physical address of the communication buffer (CBMEM)
|
||||
- `com_buffer_size`: Size in bytes of the communication buffer
|
||||
|
||||
#### - SMMSTORE_CMD_RAW_READ = 5
|
||||
|
||||
|
|
@ -208,49 +213,9 @@ 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)
|
||||
|
||||
* [A Tour Beyond BIOS Implementing UEFI Authenticated Variables in SMM with EDKI](https://software.intel.com/sites/default/files/managed/cf/ea/a_tour_beyond_bios_implementing_uefi_authenticated_variables_in_smm_with_edkii.pdf)
|
||||
Note that this differs significantly from coreboot's implementation.
|
||||
|
||||
[SMM]: ../security/smm.md
|
||||
|
|
|
|||
|
|
@ -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.
|
||||
|
|
|
|||
|
|
@ -7,10 +7,10 @@ to the point of providing its own custom language.
|
|||
The overhead of learning this new syntax is (hopefully) offset by its lower
|
||||
complexity.
|
||||
|
||||
The build system is defined in the toplevel `Makefile` and `toolchain.mk`
|
||||
The build system is defined in the toplevel `Makefile` and `toolchain.inc`
|
||||
and is supposed to be generic (and is in fact used with a number of other
|
||||
projects). Project specific configuration should reside in files called
|
||||
`Makefile.mk`.
|
||||
`Makefile.inc`.
|
||||
|
||||
In general, the build system provides a number of "classes" that describe
|
||||
various parts of the build. These cover the various build targets in coreboot
|
||||
|
|
@ -36,7 +36,7 @@ TODO: explain how to create new classes and how to evaluate them.
|
|||
### subdirs
|
||||
`subdirs` contains subdirectories (relative to the current directory) that
|
||||
should also be handled by the build system. The build system expects these
|
||||
directories to contain a file called `Makefile.mk`.
|
||||
directories to contain a file called `Makefile.inc`.
|
||||
|
||||
Subdirectories are not read at the point where the `subdirs` statement
|
||||
resides but later, after the current directory is handled (and potentially
|
||||
|
|
@ -66,7 +66,7 @@ supported options are:
|
|||
|
||||
You can use the `add_intermediate` helper to add new post-processing steps for
|
||||
the final `coreboot.rom` image. For example you can add new files to CBFS by
|
||||
adding something like this to `site-local/Makefile.mk`
|
||||
adding something like this to `site-local/Makefile.inc`
|
||||
|
||||
```
|
||||
$(call add_intermediate, add_mrc_data)
|
||||
|
|
@ -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
|
||||
|
|
@ -98,4 +100,4 @@ The default implementation just returns `COREBOOT` (the default region) for
|
|||
all files.
|
||||
|
||||
vboot provides its own implementation of `regions-for-file` that can be used
|
||||
as reference in `src/vboot/Makefile.mk`.
|
||||
as reference in `src/vboot/Makefile.inc`.
|
||||
|
|
|
|||
|
|
@ -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.
|
||||
|
|
@ -1,312 +0,0 @@
|
|||
# coreboot FAQ
|
||||
|
||||
## General coreboot questions
|
||||
|
||||
|
||||
### What is coreboot?
|
||||
|
||||
coreboot is a free and open software project designed to initialize
|
||||
computers and embedded systems in a fast, secure, and auditable fashion.
|
||||
The focus is on minimal hardware initialization: to do only what is
|
||||
absolutely needed, then pass control to other software (a payload, in
|
||||
coreboot parlance) in order to boot the operating system securely.
|
||||
|
||||
|
||||
### What is a coreboot payload?
|
||||
|
||||
coreboot itself does not deal with boot media such as hard-drives,
|
||||
SSDs, or USB flash-drives, beyond initializing the underlying hardware.
|
||||
So in order to actually boot an operating system, another piece of
|
||||
software which does do those things must be used. coreboot supports
|
||||
a large number of diverse payloads; see below for more details.
|
||||
|
||||
|
||||
### Is coreboot the same as UEFI?
|
||||
|
||||
No. coreboot and UEFI are both system firmware that handle the
|
||||
initialization of the hardware, but are otherwise not similar.
|
||||
coreboot’s goal is to **just** initialize the hardware and exit.
|
||||
This makes coreboot smaller and simpler, leading to faster boot times,
|
||||
and making it easier to find and fix bugs. The result is a higher
|
||||
overall security.
|
||||
|
||||
|
||||
### What's the difference between coreboot and UEFI?
|
||||
|
||||
UEFI is actually a firmware specification, not a specific software
|
||||
implementation. Intel, along with the rest of the Tianocore project,
|
||||
has released an open-source implementation of the overall framework,
|
||||
EDK2, but it does not come with hardware support. Most hardware running
|
||||
UEFI uses a proprietary implementation built on top of EDK2.
|
||||
|
||||
coreboot does not implement the UEFI specification, but it can be used to
|
||||
initialize the system, then launch a UEFI payload such as EDK2 in order
|
||||
to provide UEFI boot services.
|
||||
|
||||
The UEFI specification also defines and allows for many things that are
|
||||
outside of coreboot’s scope, including (but not limited to):
|
||||
|
||||
* Boot device selection
|
||||
* Updating the firmware
|
||||
* A CLI shell
|
||||
* Network communication
|
||||
* An integrated setup menu
|
||||
|
||||
|
||||
### Can coreboot boot operating systems that require UEFI?
|
||||
|
||||
Yes, but... again, coreboot **just** initializes the hardware. coreboot
|
||||
itself doesn’t load operating systems from storage media other than the
|
||||
flash chip. Unlike UEFI, coreboot does not, and will not contain a Wi-Fi
|
||||
driver or communicate directly with any sort of network. That sort of
|
||||
functionality is not related to hardware initialization.
|
||||
|
||||
To boot operating systems that require UEFI, coreboot can be compiled with
|
||||
EDK2 as the payload. This allows coreboot to perform the hardware init,
|
||||
with EDK2 supplying the UEFI boot interface and runtime services to
|
||||
the operating system.
|
||||
|
||||
|
||||
### What non-UEFI payloads does coreboot support?
|
||||
|
||||
* SeaBIOS, behaves like a classic BIOS, allowing you to boot operating
|
||||
systems that rely on the legacy interrupts.
|
||||
|
||||
* GRUB can be used as a coreboot payload, and is currently the most
|
||||
common approach to full disk encryption (FDE).
|
||||
|
||||
* A Linux kernel and initramfs stored alongside coreboot in the boot
|
||||
ROM can also be used as a payload. In this scenario coreboot
|
||||
initializes hardware, loads Linux from boot ROM into RAM, and
|
||||
executes it. The embedded Linux environment can look for a target OS
|
||||
kernel to load from local storage or over a network and execute it
|
||||
using kexec. This is sometimes called LinuxBoot.
|
||||
|
||||
* U-boot, depthcharge, FILO, etc.
|
||||
|
||||
There’s [https://doc.coreboot.org/payloads.html](https://doc.coreboot.org/payloads.html)
|
||||
with a list, although it’s not complete.
|
||||
|
||||
|
||||
### What does coreboot leave in memory after it's done initializing the hardware?
|
||||
|
||||
While coreboot tries to remove itself completely from memory after
|
||||
finishing, some tables and data need to remain for the OS. coreboot
|
||||
reserves an area in memory known as CBMEM, to save this data after it
|
||||
has finished booting. This contains things such as the boot log, tables
|
||||
that get passed to the payload, SMBIOS, and ACPI tables for the OS.
|
||||
|
||||
In addition to CBMEM, on X86 systems, coreboot will typically set up
|
||||
SMM, which will remain resident after coreboot exits.
|
||||
|
||||
|
||||
## Platforms
|
||||
|
||||
### What’s the best coreboot platform for a user?
|
||||
|
||||
The choice of the best coreboot platform for a user can vary depending
|
||||
on their specific needs, preferences, and use cases.
|
||||
|
||||
Typically, people who want a system with a minimum of proprietary
|
||||
firmware are restricted to older systems like the Lenovo X220, or more
|
||||
expensive, non-x86 solutions like TALOS, from Raptor Engineering.
|
||||
|
||||
There are a number of companies selling modern systems, but those all
|
||||
require more proprietary binaries in addition to coreboot (e.g., Intel
|
||||
FSP). However, unlike the older ThinkPads, many of these newer devices
|
||||
use open-source embedded controller (EC) firmware, so there are
|
||||
tradeoffs with either option.
|
||||
|
||||
The coreboot project mantains a list of companies selling machines
|
||||
which use coreboot on the [website](https://coreboot.org/users.html).
|
||||
|
||||
|
||||
### What’s the best platform for coreboot development?
|
||||
|
||||
Similar to the best platform for users, the best platform for
|
||||
developers very much depends on what a developer is trying to do.
|
||||
|
||||
* QEMU is generally the easiest platform for coreboot development, just
|
||||
because it’s easy to run anywhere. However, it’s possible for things
|
||||
to work properly in QEMU but fail miserably on actual hardware.
|
||||
|
||||
While laptops tend to be harder to develop than desktop platforms, a
|
||||
majority of newer platforms on coreboot tend to be laptops. The
|
||||
development difficulty is due to a few different factors:
|
||||
|
||||
1. The EC (Embedded Controller) is a specialized microcontroller that
|
||||
typically handles keyboard and sometimes mouse input for a laptop.
|
||||
It also controls many power management functions such as fans, USB-C
|
||||
power delivery, etc. ECs run mainboard-specific firmware, which is
|
||||
typically undocumented.
|
||||
2. ThinkPads (X230, 30-series, 20-series, T430, T540, T520). Sandy
|
||||
Bridge and Ivy Bridge are well-supported. Some may have
|
||||
difficult-to-reach SPI flash chips. Boards with two flash chips (e.g.
|
||||
30-series ThinkPads) are harder to externally reflash as one needs to
|
||||
make sure the non-targeted flash chip remains disabled at all times.
|
||||
The X230 is notoriously sensitive to external reflashing issues.
|
||||
3. Laptops often lack a convenient method to obtain firmware boot logs.
|
||||
One can use EHCI debug on older systems and Chromebook-specific
|
||||
solutions for Chromebooks, but one often has to resort to flashconsole
|
||||
(writing coreboot logs to the flash chip where coreboot resides). On
|
||||
the other hand, several desktop mainboards still have a RS-232 serial
|
||||
port.
|
||||
|
||||
Some of the easiest physical systems to use for coreboot development
|
||||
are Chromebooks. Newer Chromebooks allow for debug without opening the
|
||||
case. Look for SuzyQ Cables or SuzyQables or instructions on how to
|
||||
build one. These cables only work on a specific port in a specific
|
||||
orientation. Google [supplies
|
||||
specifications](https://chromium.googlesource.com/chromiumos/third_party/hdctools/+/master/docs/ccd.md#SuzyQ-SuzyQable)
|
||||
for these cables.
|
||||
|
||||
|
||||
### What platforms does coreboot support?
|
||||
|
||||
The most accurate way to determine what systems coreboot supports is by
|
||||
browsing the src/mainboard tree or running “make menuconfig” and going
|
||||
through the “Mainboard” submenu. You can also search Gerrit to see if
|
||||
there are any unmerged ports for your board.
|
||||
|
||||
There is also the board status page
|
||||
([https://coreboot.org/status/board-status.html](https://coreboot.org/status/board-status.html)),
|
||||
however this does not currently show supported board variants.
|
||||
|
||||
|
||||
## coreboot Development
|
||||
|
||||
### Can coreboot be ported to [this board]?
|
||||
|
||||
The best way to determine if coreboot can be ported to a system is to
|
||||
see if the processor and chipset is supported. The next step is to see
|
||||
whether the system is locked to the proprietary firmware which comes
|
||||
with the board.
|
||||
|
||||
Intel Platforms:
|
||||
|
||||
* coreboot only supports a few northbridges (back when northbridges
|
||||
were on a separate package), and there's next to no support for
|
||||
"server" platforms (multi-socket and similar things). Here's a list
|
||||
of more recent supported Intel processors:
|
||||
* Alder Lake (2021 - Core Gen 12)
|
||||
* Apollo Lake (2016 - Atom)
|
||||
* Baytrail (2014 - Atom)
|
||||
* Braswell (2016 - Atom)
|
||||
* Broadwell (2014 - Core Gen 5)
|
||||
* Comet Lake (2019 - Core Gen 10)
|
||||
* Cannon Lake (2018 - Core Gen 8/9)
|
||||
* Denverton (2017)
|
||||
* Elkhart lake (2021 - Atom)
|
||||
* Haswell (2013 - Core Gen 4)
|
||||
* Ivy Bridge (2012 - Core Gen 3)
|
||||
* Jasper Lake (2021 - Atom)
|
||||
* Kaby Lake (2016 - Core Gen 7/8)
|
||||
* Meteor Lake (2023 - Gen 1 Ultra-mobile)
|
||||
* Sandy Bridge (2011 - Core Gen 2)
|
||||
* Sky Lake (2015 - Core Gen 6)
|
||||
* Tiger Lake (2020 - Core Gen 11)
|
||||
* Whiskey Lake (2018 - Core Gen 8)
|
||||
|
||||
* Intel Boot Guard is a security feature which tries to prevent loading
|
||||
unauthorized firmware by the mainboard. If supported by the platform,
|
||||
and the platform is supported by intelmetool, you should check if Boot
|
||||
Guard is enabled. If it is, then getting coreboot to run will be
|
||||
difficult or impossible even if it is ported. You can run
|
||||
`intelmetool -b` on supported platforms to see if Boot Guard is
|
||||
enabled (although it can fail because it wants to probe the ME
|
||||
beforehand).
|
||||
|
||||
AMD Ryzen-based platforms:
|
||||
|
||||
* The AMD platforms Ryzen-based platforms unfortunately are currently
|
||||
not well supported outside of the Chromebooks (and AMD reference
|
||||
boards) currently in the tree.
|
||||
The responsible teams are trying to fix this, but currently it's
|
||||
**very** difficult to do a new port. Recent supported SoCs:
|
||||
* Stoney Ridge
|
||||
* Picasso
|
||||
* Cezanne
|
||||
* Mendocino
|
||||
* Phoenix
|
||||
|
||||
General notes:
|
||||
|
||||
* Check the output of `lspci` to determine what processor/chipset
|
||||
family your system has. Processor/chipset support is the most
|
||||
important to determine if a board can be ported.
|
||||
* Check the output of `superiotool` to see if it detects the Super I/O
|
||||
on the system. You can also check board schematics and/or boardviews
|
||||
if you can find them, or physically look at the mainboard for a chip
|
||||
from one of the common superio vendors.
|
||||
* Check what EC your system has (mostly applicable to laptops, but some
|
||||
desktops have EC-like chips). You will likely need to refer to the
|
||||
actual board or schematics/boardviews for this. Physical observation
|
||||
is the most accurate identification procedure; software detection can
|
||||
then be used to double-check if the chip is correct, but one should
|
||||
not rely on software detection alone to identify an EC.
|
||||
|
||||
|
||||
### How do I port coreboot to [this board]?
|
||||
|
||||
A critical piece for anyone attempting to do a board port is to make
|
||||
sure that you have a method to recover your system from a failed flash.
|
||||
|
||||
We need an updated motherboard porting guide, but currently the guide
|
||||
on the [wiki](https://www.coreboot.org/Motherboard_Porting_Guide) looks
|
||||
to be the best reference.
|
||||
|
||||
At the moment, the best answer to this question is to ask for help on
|
||||
one of the [various community
|
||||
forums](https://doc.coreboot.org/community/forums.html).
|
||||
|
||||
|
||||
### What about the Intel ME?
|
||||
|
||||
There seems to be a lot of FUD about what the ME can and can’t do.
|
||||
coreboot currently does not have a clear recommendation on how to
|
||||
handle the ME. We understand that there are serious concerns about the
|
||||
ME, and would like to flatly recommend removing as much as possible,
|
||||
however modifying the ME can cause serious stability issues.
|
||||
|
||||
Additionally, coreboot and the Intel ME are completely separate entites
|
||||
which in many cases simply happen to occupy the same flash chip. It is
|
||||
not necessary to run coreboot to modify the ME, and running coreboot
|
||||
does not imply anything about the ME's operational state.
|
||||
|
||||
|
||||
#### A word of caution about the modifying ME
|
||||
|
||||
Messing with the ME firmware can cause issues, and this is outside the
|
||||
scope of the coreboot project.
|
||||
|
||||
If you do decide to modify the ME firmware, please make sure coreboot
|
||||
works **before** messing with it. Even if the vendor boot firmware
|
||||
works when the ME isn't operating normally, it's possible that coreboot
|
||||
doesn't handle it the same way and something breaks. If someone asks
|
||||
for help with coreboot and we think the ME state may be a factor, we'll
|
||||
ask them to try reproducing the issue with the ME running normally to
|
||||
reduce the number of variables involved. This is especially important
|
||||
when flashing coreboot for the first time, as it's best for newbies to
|
||||
start with small steps: start by flashing coreboot to the BIOS region
|
||||
and leaving the remaining regions untouched, then tinker around with
|
||||
coreboot options (e.g. other payloads, bootsplash, RAM overclock...),
|
||||
or try messing with the ME firmware **without changing coreboot**.
|
||||
|
||||
Most people don't understand the implications of messing with the ME
|
||||
firmware, especially the use of `me_cleaner`. We admit that we don't
|
||||
know everything about the ME, but we try to understand it as much as
|
||||
possible. The ME is designed to operate correctly with the HAP (or
|
||||
AltMeDisable) bit set, and it will gracefully enter a debug state (not
|
||||
normal, but not an error). However, when using `me_cleaner` to remove
|
||||
parts of the ME firmware, the ME will often end up in an error state
|
||||
because parts of its FW are missing. It is known that removing some of
|
||||
these parts ([`EFFS` and `FCRS` on Cougar Point,
|
||||
c.f.](https://review.coreboot.org/c/coreboot/+/27798/6/src/mainboard/asus/p8h61-m_lx/Kconfig#63))
|
||||
can cause problems. We do not know whether the state the ME ends up in
|
||||
after applying `me_cleaner` is as secure as the state the ME goes to
|
||||
when only the HAP bit is set: the removed FW modules could contain
|
||||
steps to lock down important settings for security reasons.
|
||||
|
||||
To sum up, **we do not recommend messing with the ME firmware**. But if
|
||||
you have to, please use `ifdtool` to set the HAP bit initially before
|
||||
progressing to `me_cleaner` if necessary.
|
||||
|
|
@ -167,7 +167,7 @@ could cause catastrophic failures, up to and including your mainboard!
|
|||
As per Intel Platform Controller Hub (PCH) EDS since Skylake, a GPIO PAD register
|
||||
supports four different types of GPIO reset as:
|
||||
|
||||
```{eval-rst}
|
||||
```eval_rst
|
||||
+------------------------+----------------+-------------+-------------+
|
||||
| | | PAD Reset ? |
|
||||
+ PAD Reset Config + Platform Reset +-------------+-------------+
|
||||
|
|
|
|||
|
|
@ -1,15 +1,9 @@
|
|||
# Getting Started
|
||||
|
||||
```{toctree}
|
||||
:maxdepth: 1
|
||||
|
||||
coreboot architecture <architecture.md>
|
||||
Build System <build_system.md>
|
||||
Submodules <submodules.md>
|
||||
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>
|
||||
```
|
||||
* [coreboot architecture](architecture.md)
|
||||
* [Build System](build_system.md)
|
||||
* [Submodules](submodules.md)
|
||||
* [Kconfig](kconfig.md)
|
||||
* [Writing Documentation](writing_documentation.md)
|
||||
* [Setting up GPIOs](gpio.md)
|
||||
* [Adding devices to a device tree](devicetree.md)
|
||||
|
|
|
|||
|
|
@ -69,6 +69,9 @@ These variables are typically set in the makefiles or on the make command line.
|
|||
These variables were added to Kconfig specifically for coreboot and are not
|
||||
included in the Linux version.
|
||||
|
||||
- KCONFIG_STRICT=value. Define to enable warnings as errors. This is enabled
|
||||
in coreboot, and should not be changed.
|
||||
|
||||
- KCONFIG_NEGATIVES=value. Define to show negative values in the autoconf.h file
|
||||
(build/config.h). This is enabled in coreboot, and should not be changed.
|
||||
|
||||
|
|
@ -99,9 +102,6 @@ included in the Linux version.
|
|||
- KCONFIG_SPLITCONFIG=”directory name for individual SYMBOL.h files”.
|
||||
coreboot sets this to $(obj)/config.
|
||||
|
||||
- KCONFIG_WERROR=value. Define to enable warnings as errors. This is enabled
|
||||
in coreboot, and should not be changed.
|
||||
|
||||
#### Used only for ‘make menuconfig’
|
||||
- MENUCONFIG_MODE=single_menu. Set to "single_menu" to enable. All other
|
||||
values disable the option. This makes submenus appear below the menu option
|
||||
|
|
@ -196,9 +196,9 @@ values to be set based on other values.
|
|||
visible in the front end.
|
||||
|
||||
|
||||
### Keywords
|
||||
## Keywords
|
||||
|
||||
#### bool
|
||||
### bool
|
||||
|
||||
The 'bool' keyword assigns a boolean type to a symbol. The allowable values for
|
||||
a boolean type are 'n' or 'y'. The keyword can be followed by an optional prompt
|
||||
|
|
@ -234,7 +234,7 @@ bool \[prompt\] \[if <expr>\]
|
|||
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
#### choice
|
||||
### choice
|
||||
|
||||
This creates a selection list of one or more boolean symbols. For bools, only
|
||||
one of the symbols can be selected, and one will be be forced to be selected,
|
||||
|
|
@ -297,7 +297,7 @@ choice \[symbol\]
|
|||
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
#### comment
|
||||
### comment
|
||||
|
||||
This keyword defines a line of text that is displayed to the user in the
|
||||
configuration frontend and is additionally written to the output files.
|
||||
|
|
@ -322,7 +322,7 @@ comment <prompt>
|
|||
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
#### config
|
||||
### config
|
||||
|
||||
This is the keyword that starts a block defining a Kconfig symbol. The symbol
|
||||
modifiers follow the 'config' statement.
|
||||
|
|
@ -359,7 +359,7 @@ config <symbol>
|
|||
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
#### default
|
||||
### default
|
||||
|
||||
The ‘default’ keyword assigns a value to a symbol in the case where no preset
|
||||
value exists, i.e. the symbol is not present and assigned in .config. If there
|
||||
|
|
@ -399,7 +399,7 @@ default <expr> \[if <expr>\]
|
|||
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
#### def_bool
|
||||
### def_bool
|
||||
|
||||
‘def_bool’ is similar to the 'bool' keyword in that it sets a symbol’s type to
|
||||
boolean. It lets you set the type and default value at the same time, instead
|
||||
|
|
@ -433,7 +433,7 @@ def_bool <expr> \[if <expr>\]
|
|||
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
#### depends on
|
||||
### depends on
|
||||
|
||||
This defines a dependency for a menu entry, including symbols and comments. It
|
||||
behaves the same as surrounding the menu entry with an if/endif block. If the
|
||||
|
|
@ -462,28 +462,28 @@ depends on <expr>
|
|||
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
#### endchoice
|
||||
### endchoice
|
||||
|
||||
This ends a choice block. See the 'choice' keyword for more information and an
|
||||
example.
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
#### endif
|
||||
### endif
|
||||
|
||||
This ends a block started by the 'if' keyword. See the 'if' keyword for more
|
||||
information and an example.
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
#### endmenu
|
||||
### endmenu
|
||||
|
||||
This ends a menu block. See the 'menu' keyword for more information and an
|
||||
example.
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
#### help
|
||||
### help
|
||||
|
||||
The 'help' keyword defines the subsequent block of text as help for a config or
|
||||
choice block. The help block is started by the 'help' keyword on a line by
|
||||
|
|
@ -515,7 +515,7 @@ help <help text>
|
|||
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
#### hex
|
||||
### hex
|
||||
|
||||
This is another symbol type specifier, specifying an unsigned integer value
|
||||
formatted as hexadecimal.
|
||||
|
|
@ -551,7 +551,7 @@ hex <expr> \[if <expr>\]
|
|||
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
#### if
|
||||
### if
|
||||
|
||||
The 'if' keyword is overloaded, used in two different ways. The first definition
|
||||
enables and disables various other keywords, and follows the other keyword
|
||||
|
|
@ -592,7 +592,7 @@ endif
|
|||
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
#### int
|
||||
### int
|
||||
|
||||
A type setting keyword, defines a symbol as an integer, accepting only signed
|
||||
numeric values. The values can be further restricted with the ‘range’ keyword.
|
||||
|
|
@ -628,7 +628,7 @@ int <expr> \[if <expr>\]
|
|||
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
#### mainmenu
|
||||
### mainmenu
|
||||
|
||||
The 'mainmenu' keyword sets the title or title bar of the configuration front
|
||||
end, depending on how the configuration program decides to use it. It can only
|
||||
|
|
@ -648,7 +648,7 @@ mainmenu "coreboot configuration"
|
|||
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
#### menu
|
||||
### menu
|
||||
|
||||
The 'menu' and 'endmenu' keywords tell the configuration front end that the
|
||||
enclosed statements are part of a group of related pieces.
|
||||
|
|
@ -695,7 +695,7 @@ endmenu
|
|||
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
#### prompt
|
||||
### prompt
|
||||
|
||||
The 'prompt' keyword sets the text displayed for a config symbol or choice in
|
||||
configuration front end.
|
||||
|
|
@ -748,7 +748,7 @@ prompt <prompt> \[if <expr>\]
|
|||
prompt "Prompt value 2"
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
#### range
|
||||
### range
|
||||
|
||||
This sets the allowable minimum and maximum entries for hex or int type config
|
||||
symbols.
|
||||
|
|
@ -770,7 +770,7 @@ range <symbol> <symbol> \[if <expr>\]
|
|||
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
#### select
|
||||
### select
|
||||
|
||||
The ‘select’ keyword is used within a bool type config block. In coreboot (and
|
||||
other projects that don't use modules), the 'select' keyword can force an
|
||||
|
|
@ -814,7 +814,7 @@ select <symbol> \[if <expr>\]
|
|||
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
#### source
|
||||
### source
|
||||
|
||||
The 'source' keyword functions much the same as an 'include' statement in c.
|
||||
This pulls one or more files into Kconfig at the location of the 'source'
|
||||
|
|
@ -873,7 +873,7 @@ statements that generate a list of all the platform names:
|
|||
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
#### string
|
||||
### string
|
||||
|
||||
The last of the symbol type assignment keywords. 'string' allows a text value to
|
||||
be entered.
|
||||
|
|
@ -919,7 +919,7 @@ keyword later. See the prompt keyword for more notes.
|
|||
|
||||
|
||||
|
||||
### Keywords not used in coreboot at the time of writing:
|
||||
## Keywords not used in coreboot at the time of writing:
|
||||
|
||||
- allnoconfig_y:
|
||||
- defconfig_list
|
||||
|
|
@ -944,7 +944,7 @@ statements:
|
|||
#define SYMBOL NAME XXX
|
||||
|
||||
|
||||
#### Symbol types:
|
||||
##### Symbol types:
|
||||
- bool, int, and hex types - Every symbol of one of these types created in the
|
||||
Kconfig tree is defined. It doesn’t matter whether they’re in an if/endif
|
||||
block, or have a ‘depends on’ statement - they ALL end up being defined in
|
||||
|
|
@ -963,7 +963,7 @@ variable. This is not set in coreboot, which uses the default CONFIG_ prefix
|
|||
for all of its symbols.
|
||||
|
||||
The coreboot makefile forces the config.h file to be included into all coreboot
|
||||
C files. This is done in Makefile.mk on the compiler command line using the
|
||||
C files. This is done in Makefile.inc on the compiler command line using the
|
||||
“-include $(obj)/config.h” command line option.
|
||||
|
||||
Example of various symbol types in the config.h file:
|
||||
|
|
@ -1160,25 +1160,29 @@ saved .config file. As always, a 'select' statement overrides any specified
|
|||
- coreboot has added the glob operator '*' for the 'source' keyword.
|
||||
- coreboot’s Kconfig always defines variables except for strings. In other
|
||||
Kconfig implementations, bools set to false/0/no are not defined.
|
||||
- coreboot’s version of Kconfig adds the KCONFIG_STRICT environment variable to
|
||||
error out if there are any issues in the Kconfig files. In the Linux kernel,
|
||||
Kconfig will generate a warning, but will still output an updated .config or
|
||||
config.h file.
|
||||
|
||||
|
||||
## Kconfig Editor Highlighting
|
||||
|
||||
### vim:
|
||||
#### vim:
|
||||
|
||||
vim has syntax highlighting for Kconfig built in (or at least as a part of
|
||||
vim-common), but most editors do not.
|
||||
|
||||
|
||||
### ultraedit:
|
||||
#### ultraedit:
|
||||
|
||||
<https://github.com/martinlroth/wordfiles/blob/master/kconfig.uew>
|
||||
https://github.com/martinlroth/wordfiles/blob/master/kconfig.uew
|
||||
|
||||
|
||||
|
||||
### atom:
|
||||
#### atom:
|
||||
|
||||
<https://github.com/martinlroth/language-kconfig>
|
||||
https://github.com/martinlroth/language-kconfig
|
||||
|
||||
|
||||
## Syntax Checking:
|
||||
|
|
@ -1217,7 +1221,7 @@ in.
|
|||
## License:
|
||||
This work is licensed under the Creative Commons Attribution 4.0 International
|
||||
License. To view a copy of this license, visit
|
||||
<https://creativecommons.org/licenses/by/4.0/> or send a letter to Creative
|
||||
https://creativecommons.org/licenses/by/4.0/ or send a letter to Creative
|
||||
Commons, PO Box 1866, Mountain View, CA 94042, USA.
|
||||
|
||||
Code examples snippets are licensed under GPLv2, and are used here under fair
|
||||
|
|
|
|||
|
|
@ -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,31 @@ 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
|
||||
* sphinxcontrib-ditaa
|
||||
|
||||
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, sphinx_rtd_theme 0.4.3 and sphinxcontrib-ditaa 0.7.
|
||||
|
||||
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,19 +89,17 @@ 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:
|
||||
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:
|
||||
|
||||
| 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:
|
||||
|
||||
```{eval-rst}
|
||||
```eval_rst
|
||||
+------------+------------+-----------+
|
||||
| Header 1 | Header 2 | Header 3 |
|
||||
+============+============+===========+
|
||||
|
|
@ -113,20 +118,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:
|
||||
|
|
@ -137,7 +144,7 @@ you'll see the following warning:
|
|||
You can import CSV files and let sphinx automatically convert them to human
|
||||
readable tables, using the following reStructuredText snipped:
|
||||
|
||||
```{eval-rst}
|
||||
```eval_rst
|
||||
.. csv-table::
|
||||
:header: "Key", "Value"
|
||||
:file: keyvalues.csv
|
||||
|
|
@ -146,9 +153,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
|
||||
|
|
|
|||
|
|
@ -22,7 +22,7 @@ the power sequence timing parameters, which are usually named T[N] and also
|
|||
referenced in Intel's respective registers listing. You need the values for
|
||||
`PP_ON_DELAYS`, `PP_OFF_DELAYS` and `PP_DIVISOR` for your `devicetree.cb`:
|
||||
|
||||
```{eval-rst}
|
||||
```eval_rst
|
||||
+-----------------------------+---------------------------------------+-----+
|
||||
| Intel docs | devicetree.cb | eDP |
|
||||
+-----------------------------+---------------------------------------+-----+
|
||||
|
|
|
|||
|
|
@ -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.
|
||||
|
|
|
|||
|
|
@ -139,45 +139,6 @@ Every now and then, coreboot is present in one way or another at
|
|||
[conferences](community/conferences.md). If you're around, come and
|
||||
say hello!
|
||||
|
||||
## Blob policy in the coreboot project
|
||||
|
||||
The goal of the coreboot project is to provide a FOSS firmware solution across
|
||||
multiple CPU architectures, such as ARM, x86, and RISC-V. While fully open
|
||||
source implementations for these architectures are encouraged and preferred,
|
||||
we understand that a fully open implementation whereby every firmware component
|
||||
is available as source code for modern platforms is not always feasible.
|
||||
Different reasons inhibit the availability of fully open implementations,
|
||||
including limited development resources, 3rd party license constraints of
|
||||
IP blocks, or a legacy mindset of the silicon vendors.
|
||||
|
||||
It is important for the coreboot project to have support for modern CPU
|
||||
platforms in order to provide a viable alternative for proprietary firmware
|
||||
implementations. We do not have direct control over how hardware vendors design
|
||||
their products, however we can provide an attractive alternative to the
|
||||
expensive and complicated proprietary firmware model that exists today.
|
||||
For modern platforms, we are largely dependent on the silicon
|
||||
vendor to provide additional information on how to properly initialize the
|
||||
hardware, as the required datasheets are often only available with an NDA.
|
||||
Therefore, one possible way to have coreboot support for the latest platforms
|
||||
is binary code (aka, a blob) provided by the silicon vendor. While we do
|
||||
discourage this solution, it can be a door opener for coreboot’s support of a
|
||||
given platform and thus keep coreboot functional on modern platforms. It is
|
||||
clearly not the goal of the project to accept every blob a silicon vendor wishes
|
||||
to use without question. On the contrary, each new blob needs to be examined
|
||||
critically by the community, evaluating the need, risk, and alternative options.
|
||||
|
||||
Wherever possible, introducing new blobs should be avoided. That said, there
|
||||
can be situations where a piece of code provided as a blob will enable the rest
|
||||
of the fully open source firmware stack on a brand new platform. If blocking
|
||||
this blob would lead to no support at all for the platform in question in
|
||||
coreboot, this situation needs to be examined carefully. While these kinds
|
||||
of discussion will be coordinated closely with the community (e.g. on the
|
||||
mailing list or dedicated meetings), ultimately it is up to the leadership to
|
||||
decide if there is no agreement between the community and the vendor pushing for
|
||||
the new blob. This decision will be communicated on the mailing list.
|
||||
Please see additionally
|
||||
[coreboot binary policy](https://github.com/coreboot/blobs/blob/master/README.md).
|
||||
|
||||
## Getting the source code
|
||||
|
||||
coreboot is primarily developed in the
|
||||
|
|
@ -209,39 +170,34 @@ for example OpenBSD, is probably the closest cousin of our approach.
|
|||
|
||||
Contents:
|
||||
|
||||
```{toctree}
|
||||
:maxdepth: 1
|
||||
|
||||
Getting Started <getting_started/index.md>
|
||||
Tutorial <tutorial/index.md>
|
||||
Contributing <contributing/index.md>
|
||||
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>
|
||||
CPU Architecture <arch/index.md>
|
||||
Platform independent drivers <drivers/index.md>
|
||||
Northbridge <northbridge/index.md>
|
||||
System on Chip <soc/index.md>
|
||||
Mainboard <mainboard/index.md>
|
||||
Payloads <lib/payloads/index.md>
|
||||
Libraries <lib/index.md>
|
||||
Options <lib/option.md>
|
||||
Security <security/index.md>
|
||||
SuperIO <superio/index.md>
|
||||
Vendorcode <vendorcode/index.md>
|
||||
Utilities <util.md>
|
||||
Software Bill of Materials <sbom/sbom.md>
|
||||
Project infrastructure & services <infrastructure/index.md>
|
||||
Boards supported in each release directory <releases/boards_supported_on_branches.md>
|
||||
Release notes <releases/index.md>
|
||||
Acronyms & Definitions <acronyms.md>
|
||||
External Resources <external_docs.md>
|
||||
Documentation License <documentation_license.md>
|
||||
```
|
||||
* [Getting Started](getting_started/index.md)
|
||||
* [Tutorial](tutorial/index.md)
|
||||
* [Contributing](contributing/index.md)
|
||||
* [Community](community/index.md)
|
||||
* [Payloads](payloads.md)
|
||||
* [Distributions](distributions.md)
|
||||
* [Technotes](technotes/index.md)
|
||||
* [ACPI](acpi/index.md)
|
||||
* [Native Graphics Initialization with libgfxinit](gfx/libgfxinit.md)
|
||||
* [Display panel](gfx/display-panel.md)
|
||||
* [CPU Architecture](arch/index.md)
|
||||
* [Platform independent drivers](drivers/index.md)
|
||||
* [Northbridge](northbridge/index.md)
|
||||
* [System on Chip](soc/index.md)
|
||||
* [Mainboard](mainboard/index.md)
|
||||
* [Payloads](lib/payloads/index.md)
|
||||
* [Libraries](lib/index.md)
|
||||
* [Options](lib/option.md)
|
||||
* [Security](security/index.md)
|
||||
* [SuperIO](superio/index.md)
|
||||
* [Vendorcode](vendorcode/index.md)
|
||||
* [Utilities](util.md)
|
||||
* [Software Bill of Materials](sbom/sbom.md)
|
||||
* [Project infrastructure & services](infrastructure/index.md)
|
||||
* [Boards supported in each release directory](releases/boards_supported_on_branches.md)
|
||||
* [Release notes](releases/index.md)
|
||||
* [Acronyms & Definitions](acronyms.md)
|
||||
* [External Resources](external_docs.md)
|
||||
* [Documentation License](documentation_license.md)
|
||||
|
||||
[Documentation]: https://review.coreboot.org/plugins/gitiles/coreboot/+/refs/heads/main/Documentation/
|
||||
|
|
|
|||
|
|
@ -1,52 +0,0 @@
|
|||
# Operating our services
|
||||
|
||||
## Mailing list moderation
|
||||
|
||||
Our [mailing lists] experience the same barrage of spam mails than any
|
||||
other email address. We do have a spam filter in front of it, and
|
||||
since the lists require registration, spam ends up in the moderation
|
||||
queue. But not only spam ends up there, sometimes users send inquiries
|
||||
without registering first. It's a custom of the project to let these
|
||||
through, so that such emails can be discussed. This requires manual
|
||||
intervention.
|
||||
|
||||
This section describes the tasks related to mailing list management.
|
||||
|
||||
### Registration
|
||||
|
||||
To participate in mailing list moderation, you need to become a list
|
||||
moderator or owner. This is up for the existing owners to handle and
|
||||
if you want to contribute in that area, it might be best to bring it
|
||||
up at the leadership meeting.
|
||||
|
||||
After gaining leadership approval, list admins can add you to the
|
||||
appropriate group in the [mailing list backend] by selecting the list,
|
||||
then User / group-name, and add your email address there.
|
||||
|
||||
### Regular tasks
|
||||
|
||||
Most of our lists are auto-subscribing, so users can register
|
||||
themselves and finish the process by responding to the double-opt-in
|
||||
email. Some lists are manually managed though. The [mailing list
|
||||
backend] shows the number of open subscription requests for these
|
||||
lists on the mailing list's main page.
|
||||
|
||||
It also provides a list of held messages, where they can be accepted,
|
||||
rejected or dropped. Spam should be dropped, that's clear. Emails with
|
||||
huge attachments (e.g. screenshots) should be rejected, which gives
|
||||
you an opportunity to explain the reason (in case of large
|
||||
attachments, something like "Please re-send without attachments, offer
|
||||
the files through some other mechanism please: Our emails are
|
||||
distributed to hundreds of readers, and sending the files to everybody
|
||||
is inconsiderate of traffic and storage constraints.")
|
||||
|
||||
Legit emails (often simple requests of the form "is this or that
|
||||
supported") can be accepted, which means they'll be sent out.
|
||||
|
||||
If you notice recurring spam sources (e.g. marketers) you can put them
|
||||
on the [global ban list] to filter them out across all lists. It takes
|
||||
entries in regular expression format.
|
||||
|
||||
[mailing lists]: https://mail.coreboot.org/hyperkitty/
|
||||
[mailing list backend]: https://mail.coreboot.org/postorius/
|
||||
[global ban list]: https://mail.coreboot.org/postorius/bans/
|
||||
|
|
@ -23,6 +23,8 @@ as the system can just be disabled until someone is available to fix any
|
|||
issues.
|
||||
|
||||
Currently active Jenkins admins:
|
||||
* Patrick Georgi:
|
||||
* Email: [patrick@coreboot.org](mailto:patrick@coreboot.org)
|
||||
* Martin Roth:
|
||||
* Email: [gaumless@gmail.com](mailto:gaumless@gmail.com)
|
||||
* IRC: martinr
|
||||
|
|
|
|||
|
|
@ -100,4 +100,4 @@ are discovered and go unnoticed in a later build.
|
|||
|
||||
More projects that are hosted on review.coreboot.org (potentially as a
|
||||
mirror, like vboot and EC) could be served through that pipeline. Reach
|
||||
out to {stepan,martin}@coreboot.org.
|
||||
out to {stepan,patrick,martin}@coreboot.org.
|
||||
|
|
|
|||
|
|
@ -4,17 +4,9 @@ This section contains documentation about our infrastructure
|
|||
|
||||
## Services
|
||||
|
||||
```{toctree}
|
||||
:maxdepth: 1
|
||||
* [Project services](services.md)
|
||||
|
||||
Project services <services.md>
|
||||
Administrator's handbook <admin.md>
|
||||
```
|
||||
|
||||
## Jenkins builders and builds
|
||||
```{toctree}
|
||||
:maxdepth: 1
|
||||
|
||||
Setting up Jenkins build machines <builders.md>
|
||||
Coverity Scan integration <coverity.md>
|
||||
```
|
||||
* [Setting up Jenkins build machines](builders.md)
|
||||
* [Coverity Scan integration](coverity.md)
|
||||
|
|
|
|||
|
|
@ -41,7 +41,7 @@ stating:
|
|||
|
||||
### Gerrit user avatar
|
||||
To setup an avatar to show in Gerrit, clone the avatars repository at
|
||||
<https://review.coreboot.org/gerrit-avatars.git> and add a file named
|
||||
https://review.coreboot.org/gerrit-avatars.git and add a file named
|
||||
$your-user-ID.jpg (the user ID is a number shown on the [settings screen](https://review.coreboot.org/settings)).
|
||||
The image must be provided in JPEG format, must be square and have at most 50000
|
||||
bytes.
|
||||
|
|
|
|||
|
|
@ -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.
|
||||
|
|
@ -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.
|
||||
|
|
@ -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
|
|
@ -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>
|
||||
```
|
||||
|
|
@ -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;
|
||||
}
|
||||
```
|
||||
|
|
|
|||
|
|
@ -3,15 +3,7 @@
|
|||
This section contains documentation about coreboot internal technical
|
||||
information and libraries.
|
||||
|
||||
```{toctree}
|
||||
:maxdepth: 1
|
||||
|
||||
Flashmap and Flashmap Descriptor <flashmap.md>
|
||||
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>
|
||||
```
|
||||
- [Flashmap and Flashmap Descriptor](flashmap.md)
|
||||
- [ABI data consumption](abi-data-consumption.md)
|
||||
- [Timestamps](timestamp.md)
|
||||
- [Firmware Configuration Interface](fw_config.md)
|
||||
|
|
|
|||
|
|
@ -8,8 +8,4 @@ selected mainboard.
|
|||
|
||||
## FIT
|
||||
|
||||
```{toctree}
|
||||
:maxdepth: 1
|
||||
|
||||
uImage.FIT support <fit.md>
|
||||
```
|
||||
- [uImage.FIT support](fit.md)
|
||||
|
|
|
|||
|
|
@ -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.
|
||||
|
|
@ -1,97 +0,0 @@
|
|||
# Relocatable Modules (rmodules)
|
||||
|
||||
Relocatable modules are currently only used on x86. Relocatable
|
||||
modules are executables. Exectuables which can be executed anywhere in
|
||||
memory. Anywhere means that the module does not need to be executed
|
||||
at a defined memory address which is known at build/link time. For
|
||||
coreboot stages like bootblock and romstage it is known at build
|
||||
time at which addresses they are executed. For some exectuables it
|
||||
is however not known at which specific address they are executed in
|
||||
runtime (for example postcar and ramstage). Relocateable modules
|
||||
usually allocate the space for the modules just before they are
|
||||
supposed to be executed. After enough space is allocated, CBMEM will
|
||||
return the location of the allocated space. Now the relocation can be
|
||||
done by fixing up all relocation entries in the relocatable module
|
||||
based on the location of the binary (which was returned by CBMEM
|
||||
at runtime).
|
||||
|
||||
## Implementation Details
|
||||
|
||||
### Build Time
|
||||
|
||||
At build time the rmodtool (util/cbfstool/rmodtool.c) is used to
|
||||
create relocatable modules. The rmodtool basically takes an ELF
|
||||
file as an input and writes an ELF as output. It basically does
|
||||
a simple conversion from one ELF file to another slighty changed
|
||||
ELF file. First the tool makes sure that the ELF file fits a few
|
||||
requirements. For example there can only be one segment (loadable
|
||||
program header) in the input ELF file. After that it goes through
|
||||
the ELF relocation table and takes any entry that applies to the one
|
||||
segment we want to load at runtime. The rmodtool will then write all
|
||||
these relocation entires in a new ELF section called ".reloc". After
|
||||
that the ELF relocation table will be cleared.
|
||||
|
||||
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
|
||||
|
||||
In the end the ELF files will have three different ELF sections,
|
||||
which are all created by the rmodtool.
|
||||
1. relocation header (.header)
|
||||
2. program (.program)
|
||||
3. relocation entries (.relocs)
|
||||
|
||||
### Runtime
|
||||
|
||||
Either rmodule\_load (lib/rmodule.c) is used directly or through the
|
||||
rmodule\_stage\_load (lib/rmodule.c) wrapper. It is used to load the
|
||||
stages (postcar and ramstage) or small programs like (sipi\_vector,
|
||||
smm, smmstub) into memory before jumping to them. In the case of a
|
||||
coreboot stage, CBMEM is used to allocate space for the stage in memory
|
||||
via the rmodule\_cbfs\_allocater (lib/rmodule.c). At this point the
|
||||
location of the stage in memory is known and all relocation (address
|
||||
fixups) need to be done now. This is basically just a simple loop that
|
||||
goes through each relocation entry. Each relocation entry is just an
|
||||
address pointing to a location that needs relocation. The relocation
|
||||
itself is just a simple addition, that adds an offset from where the
|
||||
image was "supposed" to be at link time, to where it is now relocated.
|
||||
|
||||
### module\_parameters
|
||||
|
||||
module\_parameters is a section inside the rmodule ELF file. Its
|
||||
basically a way to pass runtime information to an rmodule
|
||||
before jumping to it. The caller will use rmodule\_parameters()
|
||||
(lib/rmodule.c) to get the runtime address of the module\_parameters
|
||||
and the callee (the rmodule itself) usually appends the section to
|
||||
specific types via compiler attributes. For example:
|
||||
```
|
||||
static const
|
||||
volatile __attribute((aligned(4), __section__(".module_parameters")))
|
||||
struct smm_runtime smm_runtime;
|
||||
```
|
||||
|
||||
## x86 why rmodules
|
||||
//TODO
|
||||
x86: postcar and ramstage cannot conflict with payload regarding
|
||||
memory placement. Therefore payload location is usually fixed and
|
||||
postcar/ramstage can be placed at a location in memory that is
|
||||
figured out at runtime.
|
||||
|
|
@ -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`).
|
||||
|
|
@ -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.
|
||||
|
||||
|
|
@ -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.
|
||||
|
|
|
|||
|
|
@ -5,7 +5,7 @@ Acer models Aspire M3800, Aspire M5800 and possibly more.
|
|||
|
||||
## Technology
|
||||
|
||||
```{eval-rst}
|
||||
```eval_rst
|
||||
+------------------+--------------------------------------------------+
|
||||
| Northbridge | Intel G43 (called x4x in coreboot code) |
|
||||
+------------------+--------------------------------------------------+
|
||||
|
|
@ -69,7 +69,7 @@ Tests were done with SeaBIOS 1.14.0 and slackware64-live from 2019-07-12
|
|||
|
||||
## Flashing coreboot
|
||||
|
||||
```{eval-rst}
|
||||
```eval_rst
|
||||
+-------------------+---------------------+
|
||||
| Type | Value |
|
||||
+===================+=====================+
|
||||
|
|
@ -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
|
||||
|
||||
|
|
|
|||
|
|
@ -33,7 +33,7 @@ Three items are marked in this picture
|
|||
|
||||
## Flashing coreboot
|
||||
|
||||
```{eval-rst}
|
||||
```eval_rst
|
||||
+---------------------+--------------------+
|
||||
| Type | Value |
|
||||
+=====================+====================+
|
||||
|
|
@ -53,7 +53,7 @@ Three items are marked in this picture
|
|||
|
||||
## Technology
|
||||
|
||||
```{eval-rst}
|
||||
```eval_rst
|
||||
+---------------+------------------------------+
|
||||
| Fan control | Using fintek F81803A |
|
||||
+---------------+------------------------------+
|
||||
|
|
@ -63,7 +63,7 @@ Three items are marked in this picture
|
|||
|
||||
## Description of pictures within this document
|
||||
|
||||
```{eval-rst}
|
||||
```eval_rst
|
||||
+----------------------------+----------------------------------------+
|
||||
|pademelon.jpg | Motherboard with components identified |
|
||||
+----------------------------+----------------------------------------+
|
||||
|
|
|
|||
|
|
@ -11,7 +11,7 @@ Intel company provides [Firmware Support Package (2.0)](../../soc/intel/fsp/inde
|
|||
|
||||
FSP Information:
|
||||
|
||||
```{eval-rst}
|
||||
```eval_rst
|
||||
+-----------------------------+-------------------+-------------------+
|
||||
| FSP Project Name | Directory | Specification |
|
||||
+-----------------------------+-------------------+-------------------+
|
||||
|
|
@ -114,7 +114,7 @@ facing towards the bottom of the board.
|
|||
|
||||
## Technology
|
||||
|
||||
```{eval-rst}
|
||||
```eval_rst
|
||||
+------------------+--------------------------------------------------+
|
||||
| CPU | Intel Skylake/Kaby Lake (LGA1151) |
|
||||
+------------------+--------------------------------------------------+
|
||||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -5,7 +5,7 @@ Bridge and Ivy Bridge CPUs.
|
|||
|
||||
## Technology
|
||||
|
||||
```{eval-rst}
|
||||
```eval_rst
|
||||
+------------------+--------------------------------------------------+
|
||||
| Northbridge | :doc:`../../northbridge/intel/sandybridge/index` |
|
||||
+------------------+--------------------------------------------------+
|
||||
|
|
@ -71,7 +71,7 @@ extlinux
|
|||
|
||||
## Flashing coreboot
|
||||
|
||||
```{eval-rst}
|
||||
```eval_rst
|
||||
+---------------------+------------+
|
||||
| Type | Value |
|
||||
+=====================+============+
|
||||
|
|
@ -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
|
||||
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
||||
|
|
@ -108,7 +111,7 @@ Please also see
|
|||
|
||||
## Technology
|
||||
|
||||
```{eval-rst}
|
||||
```eval_rst
|
||||
+------------------+--------------------------------------------------+
|
||||
| Northbridge | :doc:`../../northbridge/intel/haswell/index` |
|
||||
+------------------+--------------------------------------------------+
|
||||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -1,245 +0,0 @@
|
|||
# ASRock Industrial IMB-1222 Thin Mini-ITX Motherboard
|
||||
|
||||
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) |
|
||||
+---------+---------------------------------------------------------------+
|
||||
```
|
||||
|
||||
```text
|
||||
+--------------+ +---------------------------+ +---------------+
|
||||
| eDP |------------------------| |----| DDR4 SODIMM |
|
||||
+--------------+ | | +---------------+
|
||||
+--------------+ +--------------+ | | +---------------+
|
||||
| HDMI |----| ITE IT6563 |----| |----| DDR4 SODIMM |
|
||||
+--------------+ +--------------+ | | +---------------+
|
||||
+--------------+ | Intel 10th Gen |
|
||||
| Display Port |------------------------| (Comet lake-S) |
|
||||
+--------------+ | Core Processors |
|
||||
+--------------+ | LGA-1200 |
|
||||
| Display Port |------------------------| |
|
||||
+--------------+ | |
|
||||
+--------------+ +--------------+ | | +---------------+
|
||||
| LVDS |----| CH7511B-BF |----| |----| PCIe Gen3 x16 |
|
||||
+--------------+ +--------------+ +---------------------------+ +---------------+
|
||||
|
|
||||
|
|
||||
+------------------+ +---------------------------+ +---------------+
|
||||
| 4 x USB 3.2 Gen1 | | | | 2 x SATA |
|
||||
| Connector |--------------------| |----| Connector |
|
||||
+------------------+ | | +---------------+
|
||||
+------------------+ | | +---------------+
|
||||
| 2 x USB 3.2 Gen1 | | | | M.2 KeyM SATA |
|
||||
| Header |--------------------| Intel Q470E PCH |----| PCIe Gen3x4 |
|
||||
+------------------+ | | +---------------+
|
||||
+--------------+ | | +---------------+
|
||||
| 2 x USB 2.0 | | | | M.2 Key E |
|
||||
| Header |------------------------| |----| PCIe Gen3 x1/ |
|
||||
+--------------+ | | | CNVi/USB2.0 |
|
||||
+--------------+ +--------------+ | | +---------------+
|
||||
| RJ45 |----| I225LM/I225V |----| | +---------------+
|
||||
+--------------+ +--------------+ | | | M.2 Key B |
|
||||
+--------------+ +--------------+ | |----| PCIe Gen3 x1/ |
|
||||
| RJ45 |----| I219LM |----| | | USB3.0/USB2.0 |
|
||||
+--------------+ +--------------+ | | +---------------+
|
||||
+--------------+ +--------------+ | | +---------------+
|
||||
| Mic-in | | Realtek | | | | TPM INFINEON |
|
||||
| Line-out |----| ALC887 |----| |----| SLB 9670VQ2.0 |
|
||||
| SPDIF | +--------------+ | | +---------------+
|
||||
+--------------+ | +---------------------------+
|
||||
+--------------+ |
|
||||
| ALC122 | | LPC
|
||||
+--------------+ +--------------+
|
||||
+-----------------------+ +--------------+ | | +------------+
|
||||
| 2 x COM RS232/422/485 |---| ST3243E |---| Fintek |----| CPU FAN x1 |
|
||||
+-----------------------+ +--------------+ | F81966 | +------------+
|
||||
+-----------------------+ +--------------+ | SuperIO | +------------+
|
||||
| 2 x COM RS232 |---| ST3243E |---| |----| NCT 3941SA |
|
||||
+-----------------------+ +--------------+ +--------------+ +------------+
|
||||
| |
|
||||
+--------------+ +------------+
|
||||
| 8 x GPIO | | CHA FAN x1 |
|
||||
+--------------+ +------------+
|
||||
|
||||
```
|
||||
|
||||
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:
|
||||
|
||||
```bash
|
||||
make distclean
|
||||
touch .config
|
||||
./util/scripts/config --enable VENDOR_ASROCK
|
||||
./util/scripts/config --enable BOARD_ASROCK_IMB_1222
|
||||
make olddefconfig
|
||||
make
|
||||
```
|
||||
|
||||
## Payloads
|
||||
|
||||
```{eval-rst}
|
||||
+---------------+------+---------+-----------+
|
||||
| OS / Payload | EDK2 | SeaBIOS | LinuxBoot |
|
||||
+===============+======+=========+===========+
|
||||
| Ubuntu 22.04 | V | V | V |
|
||||
+---------------+------+---------+-----------+
|
||||
| Ubuntu 24.04 | V | V | V |
|
||||
+---------------+------+---------+-----------+
|
||||
| Windows 10 | V | | |
|
||||
+---------------+------+---------+-----------+
|
||||
| Windows 11 | V | | |
|
||||
+---------------+------+---------+-----------+
|
||||
| Android 13 | | V | |
|
||||
+---------------+------+---------+-----------+
|
||||
```
|
||||
|
||||
- LinuxBoot/Linux as payload;
|
||||
- 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
|
||||
|
||||
```{eval-rst}
|
||||
+---------------------+--------------------------+
|
||||
| Type | Value |
|
||||
+=====================+==========================+
|
||||
| Socketed flash | yes |
|
||||
+---------------------+--------------------------+
|
||||
| Model | | W25Q256JV |
|
||||
| | | MX25L25673G |
|
||||
+---------------------+--------------------------+
|
||||
| Size | 32 MiB |
|
||||
+---------------------+--------------------------+
|
||||
| Package | WSON-8 8x6 mm |
|
||||
+---------------------+--------------------------+
|
||||
| Write protection | chipset PRR |
|
||||
+---------------------+--------------------------+
|
||||
| Dual BIOS feature | no |
|
||||
+---------------------+--------------------------+
|
||||
| Internal flashing | after flashing coreboot |
|
||||
+---------------------+--------------------------+
|
||||
```
|
||||
|
||||
The SPI flash can be accessed using [flashrom]. By default, only the
|
||||
BIOS region of the flash is writable:
|
||||
|
||||
```bash
|
||||
flashrom -p internal -N -w coreboot.rom --ifd -i bios
|
||||
```
|
||||
|
||||
If you wish to change any other region, such as the Management Engine
|
||||
or firmware descriptor, then an external programmer is required. More
|
||||
information about this [here](../../tutorial/flashing_firmware/index.md).
|
||||
|
||||
## Working
|
||||
|
||||
- Dual Channel DDR4 2933/2666/2400 MHz;
|
||||
- Intel UHD Graphics:
|
||||
- DP (both);
|
||||
- HDMI;
|
||||
- VGA Option ROM;
|
||||
- libgfxinit;
|
||||
- GOP;
|
||||
- PCIe x16 Slot (Gen3);
|
||||
- SATA ports;
|
||||
- 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-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;
|
||||
- Realtek ALC887 HD Audio (line-out, mic-in);
|
||||
- COM 1/2/3/4 ports (Fintek f81966);
|
||||
- onboard speaker;
|
||||
- HWM/FANs control (Fintek f81966);
|
||||
- S3 suspend and wake;
|
||||
- TPM;
|
||||
- disabling ME with me_cleaner [XutaxKamay fork] (v1.2-9-gf20532d).
|
||||
|
||||
## Unknown/untested
|
||||
|
||||
- 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/
|
||||
[MrChromebox fork]: https://github.com/MrChromebox/edk2
|
||||
[XutaxKamay fork]: https://github.com/XutaxKamay/me_cleaner
|
||||
[Bliss OS]: https://blissos.org/
|
||||
|
|
@ -14,7 +14,7 @@ and their GPU is [Sea Islands] (GCN2-based).
|
|||
|
||||
A10 Richland is recommended for the best performance and working IOMMU.
|
||||
|
||||
```{eval-rst}
|
||||
```eval_rst
|
||||
+------------------+--------------------------------------------------+
|
||||
| A88XM-E | |
|
||||
+------------------+--------------------------------------------------+
|
||||
|
|
@ -36,7 +36,7 @@ A10 Richland is recommended for the best performance and working IOMMU.
|
|||
|
||||
## Flashing coreboot
|
||||
|
||||
```{eval-rst}
|
||||
```eval_rst
|
||||
+---------------------+------------+
|
||||
| Type | Value |
|
||||
+=====================+============+
|
||||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -15,7 +15,7 @@ Both "Trinity" and "Richland" desktop processing units are working,
|
|||
the CPU architecture in these CPUs/APUs is [Piledriver],
|
||||
and their GPU is [TeraScale 3] (VLIW4-based).
|
||||
|
||||
```{eval-rst}
|
||||
```eval_rst
|
||||
+------------------+--------------------------------------------------+
|
||||
| F2A85-M | |
|
||||
+------------------+--------------------------------------------------+
|
||||
|
|
@ -35,7 +35,7 @@ and their GPU is [TeraScale 3] (VLIW4-based).
|
|||
+------------------+--------------------------------------------------+
|
||||
```
|
||||
|
||||
```{eval-rst}
|
||||
```eval_rst
|
||||
+------------------+--------------------------------------------------+
|
||||
| F2A85-M LE | |
|
||||
+------------------+--------------------------------------------------+
|
||||
|
|
@ -55,7 +55,7 @@ and their GPU is [TeraScale 3] (VLIW4-based).
|
|||
+------------------+--------------------------------------------------+
|
||||
```
|
||||
|
||||
```{eval-rst}
|
||||
```eval_rst
|
||||
+------------------+--------------------------------------------------+
|
||||
| F2A85-M PRO | |
|
||||
+------------------+--------------------------------------------------+
|
||||
|
|
@ -77,7 +77,7 @@ and their GPU is [TeraScale 3] (VLIW4-based).
|
|||
|
||||
## Flashing coreboot
|
||||
|
||||
```{eval-rst}
|
||||
```eval_rst
|
||||
+---------------------+------------+
|
||||
| Type | Value |
|
||||
+=====================+============+
|
||||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
@ -10,7 +10,7 @@ This page describes how to run coreboot on the ASUS P2B-LS mainboard.
|
|||
|
||||
## Flashing coreboot
|
||||
|
||||
```{eval-rst}
|
||||
```eval_rst
|
||||
+---------------------+---------------------------+
|
||||
| Type | Value |
|
||||
+=====================+===========================+
|
||||
|
|
@ -90,7 +90,7 @@ for only CPU models that the board will actually be run with.
|
|||
|
||||
## Technology
|
||||
|
||||
```{eval-rst}
|
||||
```eval_rst
|
||||
+------------------+--------------------------------------------------+
|
||||
| Northbridge | Intel I440BX |
|
||||
+------------------+--------------------------------------------------+
|
||||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -4,7 +4,7 @@ This page describes how to run coreboot on the ASUS P3B-F mainboard.
|
|||
|
||||
## Flashing coreboot
|
||||
|
||||
```{eval-rst}
|
||||
```eval_rst
|
||||
+---------------------+---------------------------+
|
||||
| Type | Value |
|
||||
+=====================+===========================+
|
||||
|
|
@ -88,7 +88,7 @@ for only CPU models that the board will actually be run with.
|
|||
|
||||
## Technology
|
||||
|
||||
```{eval-rst}
|
||||
```eval_rst
|
||||
+------------------+--------------------------------------------------+
|
||||
| Northbridge | Intel I440BX |
|
||||
+------------------+--------------------------------------------------+
|
||||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -32,7 +32,7 @@ This page describes how to run coreboot on the [ASUS P5Q] desktop board.
|
|||
|
||||
## Flashing coreboot
|
||||
|
||||
```{eval-rst}
|
||||
```eval_rst
|
||||
+-------------------+----------------+
|
||||
| Type | Value |
|
||||
+===================+================+
|
||||
|
|
@ -56,7 +56,7 @@ You can flash coreboot into your motherboard using [this guide].
|
|||
|
||||
## Technology
|
||||
|
||||
```{eval-rst}
|
||||
```eval_rst
|
||||
+------------------+---------------------------------------------------+
|
||||
| Northbridge | Intel P45 (called x4x in coreboot code) |
|
||||
+------------------+---------------------------------------------------+
|
||||
|
|
|
|||
|
|
@ -4,7 +4,7 @@ This page describes how to run coreboot on the [ASUS P8H77-V].
|
|||
|
||||
## Flashing coreboot
|
||||
|
||||
```{eval-rst}
|
||||
```eval_rst
|
||||
+---------------------+----------------+
|
||||
| Type | Value |
|
||||
+=====================+================+
|
||||
|
|
@ -69,7 +69,7 @@ flash externally.
|
|||
|
||||
## Technology
|
||||
|
||||
```{eval-rst}
|
||||
```eval_rst
|
||||
+------------------+--------------------------------------------------+
|
||||
| Northbridge | :doc:`../../northbridge/intel/sandybridge/index` |
|
||||
+------------------+--------------------------------------------------+
|
||||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -4,7 +4,7 @@ This page describes how to run coreboot on the [ASUS P8H61-M LX].
|
|||
|
||||
## Flashing coreboot
|
||||
|
||||
```{eval-rst}
|
||||
```eval_rst
|
||||
+---------------------+------------+
|
||||
| Type | Value |
|
||||
+=====================+============+
|
||||
|
|
@ -84,7 +84,7 @@ region is not readable even by the host.
|
|||
|
||||
## Technology
|
||||
|
||||
```{eval-rst}
|
||||
```eval_rst
|
||||
+------------------+--------------------------------------------------+
|
||||
| Northbridge | :doc:`../../northbridge/intel/sandybridge/index` |
|
||||
+------------------+--------------------------------------------------+
|
||||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -4,7 +4,7 @@ This page describes how to run coreboot on the [ASUS P8H61-M Pro].
|
|||
|
||||
## Flashing coreboot
|
||||
|
||||
```{eval-rst}
|
||||
```eval_rst
|
||||
+---------------------+------------+
|
||||
| Type | Value |
|
||||
+=====================+============+
|
||||
|
|
@ -78,7 +78,7 @@ region is not readable even by the host.
|
|||
|
||||
## Technology
|
||||
|
||||
```{eval-rst}
|
||||
```eval_rst
|
||||
+------------------+--------------------------------------------------+
|
||||
| Northbridge | :doc:`../../northbridge/intel/sandybridge/index` |
|
||||
+------------------+--------------------------------------------------+
|
||||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -4,7 +4,7 @@ This page describes how to run coreboot on the [ASUS P8H77-V].
|
|||
|
||||
## Flashing coreboot
|
||||
|
||||
```{eval-rst}
|
||||
```eval_rst
|
||||
+---------------------+----------------+
|
||||
| Type | Value |
|
||||
+=====================+================+
|
||||
|
|
@ -56,7 +56,7 @@ work. The flash chip is socketed, so it's easy to remove and reflash.
|
|||
|
||||
## Technology
|
||||
|
||||
```{eval-rst}
|
||||
```eval_rst
|
||||
+------------------+--------------------------------------------------+
|
||||
| Northbridge | :doc:`../../northbridge/intel/sandybridge/index` |
|
||||
+------------------+--------------------------------------------------+
|
||||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -4,7 +4,7 @@ This page describes how to run coreboot on the [ASUS P8Z77-M].
|
|||
|
||||
## Flashing coreboot
|
||||
|
||||
```{eval-rst}
|
||||
```eval_rst
|
||||
+---------------------+----------------+
|
||||
| Type | Value |
|
||||
+=====================+================+
|
||||
|
|
@ -35,119 +35,84 @@ The flash chip is socketed, so it's easy to remove and reflash.
|
|||
## Working
|
||||
|
||||
- All USB2 ports (mouse, keyboard and thumb drive)
|
||||
- USB3 ports on rear (Boots Arch-based SystemRescue 6.0.3 off a Kingston DataTraveler G4 8GB)
|
||||
- USB3 ports on rear (Boots SystemRescue 6.0.3 off a Kingston DataTraveler G4 8GB)
|
||||
- Gigabit Ethernet (RTL8111F)
|
||||
- SATA3, SATA2 (all ports, hot-swap not tested)
|
||||
- CPU Temp sensors and hardware monitor (See [Known issues] below)
|
||||
(Blue SATA2) (Blue SATA2) (White SATA3)
|
||||
port 5 port 3 port 1
|
||||
port 6 port 4 port 2
|
||||
|
||||
- CPU Temp sensors and hardware monitor (some values don't make sense)
|
||||
- Native and MRC memory initialization
|
||||
(please see [RAM compatibility] below)
|
||||
(please see [Native raminit compatibility] and [MRC memory compatibility])
|
||||
|
||||
- Integrated graphics with both libgfxinit and the Intel Video BIOS OpROM
|
||||
(VGA/DVI-D/HDMI tested and working)
|
||||
- 16x PCIe GPU in PCIe-16x/4x slots (tested using nVidia Quadro 600 under SystemRescue 6.0.3)
|
||||
- 16x PCIe GPU in PCIe-16x/4x slots (tested using nVidia Quadro 600 under SystemRescue 6.0.3
|
||||
(Arch based))
|
||||
- Serial port
|
||||
- PCI slot
|
||||
- Rockwell HSF 56k PCI modem (detected, not function tested)
|
||||
- Sound Blaster Live! CT4780 (detected, not function tested)
|
||||
- Promise SATA150 TX2plus (R/W OK to connected IDE hard drive, OpRom loaded, cannot boot from
|
||||
Rockwell HSF 56k PCI modem, Sound Blaster Live! CT4780 (cards detected, not function tested)
|
||||
Promise SATA150 TX2plus (R/W OK to connected IDE hard drive, OpRom loaded, cannot boot from
|
||||
SeaBIOS)
|
||||
- PCIe x1 slot
|
||||
- MSI Herald-BE (Qualcomm NCM865 m.2 Wifi 7 module via PCIe-m.2 adaptor)
|
||||
- LPC POST card manually wired to TPM header
|
||||
- S3 suspend from Linux
|
||||
- 2-channel analog audio (WAV playback by mplayer via back panel line out port)
|
||||
- HDMI digital audio
|
||||
- Windows 10 with libgfxinit high resolution framebuffer and VBT
|
||||
- UEFI boot into Fedora 38 through 41 with edk2 payload (202306 mrchromebox fork)
|
||||
- PS/2 keyboard (IBM Model M #1391401 & original Microsoft Natural) with edk2 payload
|
||||
|
||||
## Known issues
|
||||
|
||||
- If you use MRC raminit, the NVRAM variable gfx_uma_size may be ignored as IGP's UMA could
|
||||
be reconfigured by the blob.
|
||||
|
||||
- Sometimes only half the memory is initialized, and/or at reduced speed. This is being
|
||||
investigated.
|
||||
|
||||
- If SeaBIOS is used for payload with libgfxinit, it must be brought in via coreboot's config.
|
||||
Otherwise integrated graphics would fail with a black screen.
|
||||
|
||||
- PCI POST card is not functional because the PCI bridge early init is not yet done.
|
||||
|
||||
- Although the black PCIEX16_2 slot can physically fit an x16 card, it only has physical
|
||||
contacts for x8, and is electrically x4 only.
|
||||
|
||||
- PS/2 keyboard may not work with SeaBIOS payload.
|
||||
|
||||
- These lm_sensors configurations are needed for hardware monitor values to make sense:
|
||||
|
||||
```bash
|
||||
label in1 "+12V"
|
||||
label in4 "+5V"
|
||||
compute in1 @*12, @/12
|
||||
compute in4 @*5, @/5
|
||||
# ...
|
||||
set temp1_type 4
|
||||
set temp2_type 4
|
||||
|
||||
```
|
||||
- The black PCIEX16_2 slot, although can physically fit an x16, only has physical contacts for
|
||||
an x8, and is electrically an x4 only.
|
||||
|
||||
## Untested
|
||||
|
||||
- Wake-on-LAN
|
||||
- USB3 on header
|
||||
- TPM module
|
||||
- TPM header
|
||||
- EHCI debugging (Debug port is on the 5-pin side of USB2_910 header)
|
||||
- S/PDIF audio out
|
||||
- HDMI and S/PDIF audio out
|
||||
|
||||
## Not working
|
||||
|
||||
- PS/2 mouse (a patch has been submitted for review)
|
||||
- PS/2 keyboard or mouse
|
||||
- 4 and 6 channel analog audio out: Rear left and right audio is a muted
|
||||
copy of front left and right audio, and the other two channels are silent.
|
||||
|
||||
## RAM compatibility
|
||||
|
||||
### Native and MRC raminit:
|
||||
## Native (and MRC) raminit compatibility
|
||||
|
||||
- OCZ OCZ3G1600LVAM 2x2GB kit works at DDR3-1066 instead of DDR3-1600.
|
||||
|
||||
- GSkill F3-1600C9D-16GRSL 2x8GB SODIMM kit on adapter boots, but is highly unstable
|
||||
with obvious pattern of bit errors during memtest86+ runs.
|
||||
|
||||
- Samsung PC3-10600U 2x2GB kit works at full rated speed.
|
||||
- GSkill F3-1600C9D-16GRSL 2x8GB SODIMM kit on unbranded adapter works at full rated speed.
|
||||
|
||||
### MRC raminit:
|
||||
|
||||
- Corsair ValueSelect CMSO4GX3M1C1600C11 4GB SODIMM works at full rated speed
|
||||
on an unbranded adapter.
|
||||
- Samsung M471B5273DH0 4GB SODIMM on adapter works at full rated speed.
|
||||
|
||||
### Native raminit:
|
||||
|
||||
- Kingston KTH9600B-4G 2x4GB kit works at full rated speed.
|
||||
- Samsung M471B5273DH0 4GB SODIMM on adapter works only at DDR3-1066 if max_mem_clock_mhz
|
||||
is reduced to 666, and only one module would be detected. It will completely fail to
|
||||
train if max_mem_clock_mhz is set to 800.
|
||||
- Corsair modules on channel 1 fails training and is unusable.
|
||||
- Two Patriot PV316G160C9K 2x8GB kits in all slots work at full rated speed.
|
||||
|
||||
## Extra onboard buttons
|
||||
|
||||
The board has two onboard buttons, each with a related LED nearby.
|
||||
The board has two onboard buttons, and each has a related LED nearby.
|
||||
What controls the LEDs and what the buttons control are unknown,
|
||||
therefore they currently do nothing under coreboot.
|
||||
|
||||
- `BIOS_FLBK` / `FLBK_LED`:
|
||||
- BIOS_FLBK
|
||||
OEM firmware uses this button to facilitate a simple update mechanism
|
||||
via a USB drive plugged into the bottom USB port of the USB/LAN stack.
|
||||
They are connected to a proprietary AI1314 microcontroller.
|
||||
They currently do nothing under coreboot.
|
||||
|
||||
- `MemOK!` / `DRAM_LED`:
|
||||
- MemOK!
|
||||
OEM firmware uses this button for memory tuning related to overclocking.
|
||||
They are connected to the NCT6779D super I/O chip.
|
||||
Button is connected to pin 74, and currently do nothing under coreboot.
|
||||
DRAM_LED is connected to GP07 pin. Active low. Since commit f7ed007298e0
|
||||
coreboot lights it up during early boot similar to vendor firmware.
|
||||
|
||||
## Technology
|
||||
|
||||
```{eval-rst}
|
||||
```eval_rst
|
||||
+------------------+--------------------------------------------------+
|
||||
| Northbridge | :doc:`../../northbridge/intel/sandybridge/index` |
|
||||
+------------------+--------------------------------------------------+
|
||||
|
|
@ -167,6 +132,6 @@ The board has two onboard buttons, each with a related LED nearby.
|
|||
|
||||
- [Flash chip datasheet][W25Q64FVA1Q]
|
||||
|
||||
[ASUS P8Z77-M]: https://www.asus.com/supportonly/p8z77-m/helpdesk_manual/
|
||||
[ASUS P8Z77-M]: https://www.asus.com/Motherboards/P8Z77M/
|
||||
[W25Q64FVA1Q]: https://www.winbond.com/resource-files/w25q64fv%20revs%2007182017.pdf
|
||||
[flashrom]: https://flashrom.org/
|
||||
[flashrom]: https://flashrom.org/Flashrom
|
||||
|
|
|
|||
|
|
@ -4,7 +4,7 @@ This page describes how to run coreboot on the [ASUS P8Z77-M PRO]
|
|||
|
||||
## Flashing coreboot
|
||||
|
||||
```{eval-rst}
|
||||
```eval_rst
|
||||
+---------------------+----------------+
|
||||
| Type | Value |
|
||||
+=====================+================+
|
||||
|
|
@ -143,7 +143,7 @@ easy to remove and reflash.
|
|||
|
||||
## Technology
|
||||
|
||||
```{eval-rst}
|
||||
```eval_rst
|
||||
+------------------+--------------------------------------------------+
|
||||
| Northbridge | :doc:`../../northbridge/intel/sandybridge/index` |
|
||||
+------------------+--------------------------------------------------+
|
||||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -4,7 +4,7 @@ This page describes how to run coreboot on the [ASUS P8Z77-V].
|
|||
|
||||
## Flashing coreboot
|
||||
|
||||
```{eval-rst}
|
||||
```eval_rst
|
||||
+---------------------+----------------+
|
||||
| Type | Value |
|
||||
+=====================+================+
|
||||
|
|
@ -86,7 +86,7 @@ See [Asus Wi-Fi Go! v1].
|
|||
|
||||
## Technology
|
||||
|
||||
```{eval-rst}
|
||||
```eval_rst
|
||||
+------------------+--------------------------------------------------+
|
||||
| Northbridge | :doc:`../../northbridge/intel/sandybridge/index` |
|
||||
+------------------+--------------------------------------------------+
|
||||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
@ -8,7 +8,7 @@ through a proprietary 16-1 pin connector.
|
|||
I managed to grope the most pinout of the proprietary connector.
|
||||
See [Mini PCIe pinout] for more info.
|
||||
|
||||
```{eval-rst}
|
||||
```eval_rst
|
||||
+------------+----------+-----------+------------+----------+-----------+
|
||||
| WIFIGO Pin | Usage | mPCIe pin | WIFIGO Pin | Usage | mPCIe pin |
|
||||
+============+==========+===========+============+==========+===========+
|
||||
|
|
|
|||
|
|
@ -17,7 +17,7 @@
|
|||
|
||||
## Flashing coreboot
|
||||
|
||||
```{eval-rst}
|
||||
```eval_rst
|
||||
+---------------------+----------------+
|
||||
| Type | Value |
|
||||
+=====================+================+
|
||||
|
|
@ -58,7 +58,7 @@
|
|||
|
||||
## Technology
|
||||
|
||||
```{eval-rst}
|
||||
```eval_rst
|
||||
+---------------+----------------------------------------+
|
||||
| SoC | :doc:`../../soc/cavium/cn81xx/index` |
|
||||
+---------------+----------------------------------------+
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@
|
|||
|
||||
## Hardware
|
||||
### Technology
|
||||
```{eval-rst}
|
||||
```eval_rst
|
||||
+------------------+--------------------------------+
|
||||
| CPU | Intel i7-8550U |
|
||||
+------------------+--------------------------------+
|
||||
|
|
@ -15,7 +15,7 @@
|
|||
```
|
||||
|
||||
### Flash chip
|
||||
```{eval-rst}
|
||||
```eval_rst
|
||||
+---------------------+-----------------+
|
||||
| Type | Value |
|
||||
+=====================+=================+
|
||||
|
|
|
|||
|
|
@ -1,83 +0,0 @@
|
|||
# Dell Latitude E7240
|
||||
|
||||
This page is about the notebook [Dell Latitude E7240].
|
||||
|
||||
## Release status
|
||||
|
||||
Dell Latitude E7240 was released in 2013 and is now end of life.
|
||||
It can be bought from a secondhand market like Taobao or eBay.
|
||||
|
||||
## Required proprietary blobs
|
||||
|
||||
The following blobs are required to operate the hardware:
|
||||
1. mrc.bin
|
||||
2. Intel ME firmware
|
||||
|
||||
Memory reference code in mrc.bin is used to initialize the Haswell platform.
|
||||
You need this blob to build a working coreboot image. Please read
|
||||
[mrc.bin](../../northbridge/intel/haswell/mrc.bin) for instructions on
|
||||
retrieving and using it.
|
||||
|
||||
Intel ME firmware is in the flash chip. It is not needed when building coreboot.
|
||||
It can be extracted from the OEM firmware. You can also flash only the BIOS
|
||||
region to leave Intel ME firmware untouched.
|
||||
|
||||
## Programming
|
||||
|
||||
The laptop can be flashed internally under OEM firmware using [dell-flash-unlock].
|
||||
|
||||
To flash with an external programmer, you need to remove the battery and the base cover.
|
||||
|
||||

|
||||
|
||||
For more details have a look at the general [flashing tutorial].
|
||||
|
||||
It is also possible to flash internally under coreboot.
|
||||
|
||||
## Debugging
|
||||
|
||||
The board can be debugged with EHCI debug. The EHCI debug port is next to the miniDP port.
|
||||
|
||||
There's a serial port on dock, but it's not yet supported in coreboot.
|
||||
|
||||
Schematic of this laptop can be found online. The board name is Compal LA-9431P.
|
||||
|
||||
## Test status
|
||||
|
||||
### Not working
|
||||
|
||||
- EC ACPI
|
||||
- SD/MMC card reader (kernel reports "Timeout waiting for hardware cmd interrupt.")
|
||||
- No internal display before booting to OS when connected with a dock
|
||||
|
||||
### Working
|
||||
|
||||
- Integrated graphics init with libgfxinit
|
||||
- mSATA
|
||||
- WLAN
|
||||
- USB
|
||||
- Keyboard
|
||||
- Touchpad and the buttons on it
|
||||
- Dock: all USB ports, DisplayPort, eSATA
|
||||
- Internal flashing
|
||||
|
||||
|
||||
## Technology
|
||||
|
||||
```{eval-rst}
|
||||
+------------------+-----------------------------+
|
||||
| CPU | Intel Haswell-ULT |
|
||||
+------------------+-----------------------------+
|
||||
| PCH | Intel Lynx Point Low Power |
|
||||
+------------------+-----------------------------+
|
||||
| EC | SMSC MEC5075 |
|
||||
+------------------+-----------------------------+
|
||||
| Super I/O | SMSC ECE5048 |
|
||||
+------------------+-----------------------------+
|
||||
| Coprocessor | Intel Management Engine |
|
||||
+------------------+-----------------------------+
|
||||
```
|
||||
|
||||
[Dell Latitude E7240]: https://www.dell.com/support/home/en-us/product-support/product/latitude-e7240-ultrabook/docs
|
||||
[dell-flash-unlock]: https://github.com/nic3-14159/dell-flash-unlock
|
||||
[flashing tutorial]: ../../tutorial/flashing_firmware/ext_power.md
|
||||
Binary file not shown.
|
Before Width: | Height: | Size: 97 KiB |
|
|
@ -6,7 +6,7 @@ This page describes how to run coreboot on Dell OptiPlex 9010 SFF.
|
|||
|
||||
## Technology
|
||||
|
||||
```{eval-rst}
|
||||
```eval_rst
|
||||
+------------+---------------------------------------------------------------+
|
||||
| CPU | Intel Core 2nd Gen (Sandybridge) or 3rd Gen (Ivybridge) |
|
||||
+------------+---------------------------------------------------------------+
|
||||
|
|
@ -28,7 +28,7 @@ More specifications on [Dell OptiPlex 9010 specifications].
|
|||
|
||||
## Required proprietary blobs
|
||||
|
||||
```{eval-rst}
|
||||
```eval_rst
|
||||
+------------------+---------------------------------+---------------------+
|
||||
| Binary file | Apply | Required / Optional |
|
||||
+==================+=================================+=====================+
|
||||
|
|
@ -50,7 +50,7 @@ signature `SMSCUBIM`. The easiest way to do this is to use [UEFITool] and
|
|||
|
||||
## Flashing coreboot
|
||||
|
||||
```{eval-rst}
|
||||
```eval_rst
|
||||
+---------------------+--------------------------+
|
||||
| Type | Value |
|
||||
+=====================+==========================+
|
||||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -3,9 +3,6 @@
|
|||
## Building coreboot and running it in QEMU
|
||||
|
||||
- Configure coreboot and run `make` as usual
|
||||
|
||||
Run QEMU
|
||||
```
|
||||
qemu-system-riscv64 -M virt -m 1G -nographic -bios build/coreboot.rom \
|
||||
-drive if=pflash,file=./build/coreboot.rom,format=raw
|
||||
```
|
||||
- Run `util/riscv/make-spike-elf.sh build/coreboot.rom build/coreboot.elf` to
|
||||
convert coreboot to an ELF that QEMU can load
|
||||
- Run `qemu-system-riscv64 -M virt -m 1024M -nographic -kernel build/coreboot.elf`
|
||||
|
|
|
|||
Some files were not shown because too many files have changed in this diff Show more
Loading…
Add table
Add a link
Reference in a new issue